From 7ce969b312688e8f852ac568351990f6b22afd74 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 23 Feb 2016 17:59:00 +0100 Subject: [PATCH 01/33] started working on more flexible model generation using next-state-generators Former-commit-id: 805940f1790292223f9216cc9dd146af12d3d6c8 --- src/CMakeLists.txt | 4 + src/builder/ExplicitPrismModelBuilder.cpp | 39 +---- src/builder/ExplicitPrismModelBuilder.h | 54 ------- src/generator/Choice.cpp | 111 ++++++++++++++ src/generator/Choice.h | 158 ++++++++++++++++++++ src/generator/NextStateGenerator.h | 27 ++++ src/generator/PrismNextStateGenerator.cpp | 22 +++ src/generator/PrismNextStateGenerator.h | 32 ++++ src/generator/prism/VariableInformation.cpp | 44 ++++++ src/generator/prism/VariableInformation.h | 73 +++++++++ src/storage/Distribution.cpp | 52 +++---- src/storage/Distribution.h | 12 +- 12 files changed, 504 insertions(+), 124 deletions(-) create mode 100644 src/generator/Choice.cpp create mode 100644 src/generator/Choice.h create mode 100644 src/generator/NextStateGenerator.h create mode 100644 src/generator/PrismNextStateGenerator.cpp create mode 100644 src/generator/PrismNextStateGenerator.h create mode 100644 src/generator/prism/VariableInformation.cpp create mode 100644 src/generator/prism/VariableInformation.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5b06a498d..0a5832d87 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,8 @@ file(GLOB_RECURSE STORM_SOURCES_CLI ${PROJECT_SOURCE_DIR}/src/cli/*.cpp) file(GLOB_RECURSE STORM_MAIN_FILE ${PROJECT_SOURCE_DIR}/src/storm.cpp) file(GLOB_RECURSE STORM_ADAPTERS_FILES ${PROJECT_SOURCE_DIR}/src/adapters/*.h ${PROJECT_SOURCE_DIR}/src/adapters/*.cpp) file(GLOB_RECURSE STORM_BUILDER_FILES ${PROJECT_SOURCE_DIR}/src/builder/*.h ${PROJECT_SOURCE_DIR}/src/builder/*.cpp) +file(GLOB STORM_GENERATOR_FILES ${PROJECT_SOURCE_DIR}/src/generator/*.h ${PROJECT_SOURCE_DIR}/src/generator/*.cpp) +file(GLOB_RECURSE STORM_GENERATOR_PRISM_FILES ${PROJECT_SOURCE_DIR}/src/generator/prism/*.h ${PROJECT_SOURCE_DIR}/src/generator/prism/*.cpp) file(GLOB_RECURSE STORM_CLI_FILES ${PROJECT_SOURCE_DIR}/src/cli/*.h ${PROJECT_SOURCE_DIR}/src/cli/*.cpp) file(GLOB_RECURSE STORM_EXCEPTIONS_FILES ${PROJECT_SOURCE_DIR}/src/exceptions/*.h ${PROJECT_SOURCE_DIR}/src/exceptions/*.cpp) file(GLOB_RECURSE STORM_LOGIC_FILES ${PROJECT_SOURCE_DIR}/src/logic/*.h ${PROJECT_SOURCE_DIR}/src/logic/*.cpp) @@ -57,6 +59,8 @@ set(STORM_MAIN_HEADERS ${STORM_HEADERS_CLI}) source_group(main FILES ${STORM_MAIN_FILE}) source_group(adapters FILES ${STORM_ADAPTERS_FILES}) source_group(builder FILES ${STORM_BUILDER_FILES}) +source_group(generator FILES ${STORM_GENERATOR_FILES}) +source_group(generator\\prism FILES ${STORM_GENERATOR_PRISM_FILES}) source_group(cli FILES ${STORM_CLI_FILES}) source_group(exceptions FILES ${STORM_EXCEPTIONS_FILES}) source_group(logic FILES ${STORM_LOGIC_FILES}) diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp index d7c2f6293..19b115c6e 100644 --- a/src/builder/ExplicitPrismModelBuilder.cpp +++ b/src/builder/ExplicitPrismModelBuilder.cpp @@ -75,44 +75,7 @@ namespace storm { ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::InternalStateInformation::InternalStateInformation(uint64_t bitsPerState) : stateStorage(bitsPerState, 10000000), bitsPerState(bitsPerState), reachableStates() { // Intentionally left empty. } - - template <typename ValueType, typename RewardModelType, typename IndexType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::VariableInformation::BooleanVariableInformation::BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset) : variable(variable), initialValue(initialValue), bitOffset(bitOffset) { - // Intentionally left empty. - } - - template <typename ValueType, typename RewardModelType, typename IndexType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::VariableInformation::IntegerVariableInformation::IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth) : variable(variable), initialValue(initialValue), lowerBound(lowerBound), upperBound(upperBound), bitOffset(bitOffset), bitWidth(bitWidth) { - // Intentionally left empty. - } - - template <typename ValueType, typename RewardModelType, typename IndexType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::VariableInformation::VariableInformation(storm::expressions::ExpressionManager const& manager) : manager(manager) { - // Intentionally left empty. - } - - template <typename ValueType, typename RewardModelType, typename IndexType> - uint_fast64_t ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::VariableInformation::getBitOffset(storm::expressions::Variable const& variable) const { - auto const& booleanIndex = booleanVariableToIndexMap.find(variable); - if (booleanIndex != booleanVariableToIndexMap.end()) { - return booleanVariables[booleanIndex->second].bitOffset; - } - auto const& integerIndex = integerVariableToIndexMap.find(variable); - if (integerIndex != integerVariableToIndexMap.end()) { - return integerVariables[integerIndex->second].bitOffset; - } - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit index of unknown variable."); - } - - template <typename ValueType, typename RewardModelType, typename IndexType> - uint_fast64_t ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::VariableInformation::getBitWidth(storm::expressions::Variable const& variable) const { - auto const& integerIndex = integerVariableToIndexMap.find(variable); - if (integerIndex != integerVariableToIndexMap.end()) { - return integerVariables[integerIndex->second].bitWidth; - } - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit width of unknown variable."); - } - + template <typename ValueType, typename RewardModelType, typename IndexType> ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), rewardModels(), choiceLabeling() { // Intentionally left empty. diff --git a/src/builder/ExplicitPrismModelBuilder.h b/src/builder/ExplicitPrismModelBuilder.h index ccb0622e7..9bd62ad2b 100644 --- a/src/builder/ExplicitPrismModelBuilder.h +++ b/src/builder/ExplicitPrismModelBuilder.h @@ -74,60 +74,6 @@ namespace storm { } }; - // A structure storing information about the used variables of the program. - struct VariableInformation { - VariableInformation(storm::expressions::ExpressionManager const& manager); - - struct BooleanVariableInformation { - BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset); - - // The boolean variable. - storm::expressions::Variable variable; - - // Its initial value. - bool initialValue; - - // Its bit offset in the compressed state. - uint_fast64_t bitOffset; - }; - - struct IntegerVariableInformation { - IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth); - - // The integer variable. - storm::expressions::Variable variable; - - // Its initial value. - int_fast64_t initialValue; - - // The lower bound of its range. - int_fast64_t lowerBound; - - // The upper bound of its range. - int_fast64_t upperBound; - - // Its bit offset in the compressed state. - uint_fast64_t bitOffset; - - // Its bit width in the compressed state. - uint_fast64_t bitWidth; - }; - - // Provide methods to access the bit offset and width of variables in the compressed state. - uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const; - uint_fast64_t getBitWidth(storm::expressions::Variable const& variable) const; - - // The known boolean variables. - boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> booleanVariableToIndexMap; - std::vector<BooleanVariableInformation> booleanVariables; - - // The known integer variables. - boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> integerVariableToIndexMap; - std::vector<IntegerVariableInformation> integerVariables; - - storm::expressions::ExpressionManager const& manager; - }; - // A structure holding the individual components of a model. struct ModelComponents { ModelComponents(); diff --git a/src/generator/Choice.cpp b/src/generator/Choice.cpp new file mode 100644 index 000000000..3b6609ebd --- /dev/null +++ b/src/generator/Choice.cpp @@ -0,0 +1,111 @@ +#include "src/generator/Choice.h" + +#include "src/utility/constants.h" + +namespace storm { + namespace generator { + + template<typename ValueType, typename StateType> + Choice<ValueType, StateType>::Choice(uint_fast64_t actionIndex, bool markovian) : markovian(markovian), actionIndex(actionIndex), distribution(), totalMass(storm::utility::zero<ValueType>()), choiceReward(storm::utility::zero<ValueType>()) { + // Intentionally left empty. + } + + template<typename ValueType, typename StateType> + typename storm::storage::Distribution<ValueType, StateType>::iterator Choice<ValueType, StateType>::begin() { + return distribution.begin(); + } + + template<typename ValueType, typename StateType> + typename storm::storage::Distribution<ValueType, StateType>::const_iterator Choice<ValueType, StateType>::begin() const { + return distribution.cbegin(); + } + + template<typename ValueType, typename StateType> + typename storm::storage::Distribution<ValueType, StateType>::iterator Choice<ValueType, StateType>::end() { + return distribution.end(); + } + + template<typename ValueType, typename StateType> + typename storm::storage::Distribution<ValueType, StateType>::const_iterator Choice<ValueType, StateType>::end() const { + return distribution.cend(); + } + + template<typename ValueType, typename StateType> + void Choice<ValueType, StateType>::addChoiceLabel(uint_fast64_t label) { + if (!choiceLabels) { + choiceLabels = LabelSet(); + } + choiceLabels->insert(label); + } + + template<typename ValueType, typename StateType> + void Choice<ValueType, StateType>::addChoiceLabels(LabelSet const& labelSet) { + if (!choiceLabels) { + choiceLabels = LabelSet(); + } + choiceLabels->insert(labelSet.begin(), labelSet.end()); + } + + template<typename ValueType, typename StateType> + boost::container::flat_set<uint_fast64_t> const& Choice<ValueType, StateType>::getChoiceLabels() const { + return *choiceLabels; + } + + template<typename ValueType, typename StateType> + uint_fast64_t Choice<ValueType, StateType>::getActionIndex() const { + return actionIndex; + } + + template<typename ValueType, typename StateType> + ValueType Choice<ValueType, StateType>::getTotalMass() const { + return totalMass; + } + + template<typename ValueType, typename StateType> + ValueType& Choice<ValueType, StateType>::getOrAddEntry(StateType const& state) { + auto stateProbabilityPair = distribution.find(state); + + if (stateProbabilityPair == distribution.end()) { + distribution[state] = ValueType(); + } + return distribution.at(state); + } + + template<typename ValueType, typename StateType> + ValueType const& Choice<ValueType, StateType>::getOrAddEntry(StateType const& state) const { + auto stateProbabilityPair = distribution.find(state); + + if (stateProbabilityPair == distribution.end()) { + distribution[state] = ValueType(); + } + return distribution.at(state); + } + + template<typename ValueType, typename StateType> + void Choice<ValueType, StateType>::addProbability(StateType const& state, ValueType const& value) { + totalMass += value; + distribution[state] += value; + } + + template<typename ValueType, typename StateType> + void Choice<ValueType, StateType>::addChoiceReward(ValueType const& value) { + choiceReward += value; + } + + template<typename ValueType, typename StateType> + std::size_t Choice<ValueType, StateType>::size() const { + return distribution.size(); + } + + template<typename ValueType, typename StateType> + std::ostream& operator<<(std::ostream& out, Choice<ValueType, StateType> const& choice) { + out << "<"; + for (auto const& stateProbabilityPair : choice) { + out << stateProbabilityPair.first << " : " << stateProbabilityPair.second << ", "; + } + out << ">"; + return out; + } + + } +} \ No newline at end of file diff --git a/src/generator/Choice.h b/src/generator/Choice.h new file mode 100644 index 000000000..07eb6efbe --- /dev/null +++ b/src/generator/Choice.h @@ -0,0 +1,158 @@ +#ifndef STORM_GENERATOR_CHOICE_H_ +#define STORM_GENERATOR_CHOICE_H_ + +#include <cstdint> +#include <functional> + +#include <boost/optional.hpp> +#include <boost/container/flat_set.hpp> + +#include "src/storage/Distribution.h" + +namespace storm { + namespace generator { + + // A structure holding information about a particular choice. + template<typename ValueType, typename StateType=uint32_t> + struct Choice { + public: + typedef boost::container::flat_set<uint_fast64_t> LabelSet; + + Choice(uint_fast64_t actionIndex = 0, bool markovian = false); + + Choice(Choice const& other) = default; + Choice& operator=(Choice const& other) = default; + Choice(Choice&& other) = default; + Choice& operator=(Choice&& other) = default; + + /*! + * Returns an iterator to the distribution associated with this choice. + * + * @return An iterator to the first element of the distribution. + */ + typename storm::storage::Distribution<ValueType, StateType>::iterator begin(); + + /*! + * Returns an iterator to the distribution associated with this choice. + * + * @return An iterator to the first element of the distribution. + */ + typename storm::storage::Distribution<ValueType, StateType>::const_iterator begin() const; + + /*! + * Returns an iterator past the end of the distribution associated with this choice. + * + * @return An iterator past the end of the distribution. + */ + typename storm::storage::Distribution<ValueType, StateType>::iterator end(); + + /*! + * Returns an iterator past the end of the distribution associated with this choice. + * + * @return An iterator past the end of the distribution. + */ + typename storm::storage::Distribution<ValueType, StateType>::const_iterator end() const; + + /*! + * Inserts the contents of this object to the given output stream. + * + * @param out The stream in which to insert the contents. + */ + template<typename ValueTypePrime, typename StateTypePrime> + friend std::ostream& operator<<(std::ostream& out, Choice<ValueTypePrime, StateTypePrime> const& choice); + + /*! + * Adds the given label to the labels associated with this choice. + * + * @param label The label to associate with this choice. + */ + void addChoiceLabel(uint_fast64_t label); + + /*! + * Adds the given label set to the labels associated with this choice. + * + * @param labelSet The label set to associate with this choice. + */ + void addChoiceLabels(LabelSet const& labelSet); + + /*! + * Retrieves the set of labels associated with this choice. + * + * @return The set of labels associated with this choice. + */ + LabelSet const& getChoiceLabels() const; + + /*! + * Retrieves the index of the action of this choice. + * + * @return The index of the action of this choice. + */ + uint_fast64_t getActionIndex() const; + + /*! + * Retrieves the total mass of this choice. + * + * @return The total mass. + */ + ValueType getTotalMass() const; + + /*! + * Retrieves the entry in the choice that is associated with the given state and creates one if none exists, + * yet. + * + * @param state The state for which to add the entry. + * @return A reference to the entry that is associated with the given state. + */ + ValueType& getOrAddEntry(StateType const& state); + + /*! + * Retrieves the entry in the choice that is associated with the given state and creates one if none exists, + * yet. + * + * @param state The state for which to add the entry. + * @return A reference to the entry that is associated with the given state. + */ + ValueType const& getOrAddEntry(StateType const& state) const; + + /*! + * Adds the given probability value to the given state in the underlying distribution. + */ + void addProbability(StateType const& state, ValueType const& value); + + /*! + * Adds the given value to the reward associated with this choice. + */ + void addChoiceReward(ValueType const& value); + + /*! + * Retrieves the size of the distribution associated with this choice. + */ + std::size_t size() const; + + private: + // A flag indicating whether this choice is Markovian or not. + bool markovian; + + // The action index associated with this choice. + uint_fast64_t actionIndex; + + // The distribution that is associated with the choice. + storm::storage::Distribution<ValueType, StateType> distribution; + + // The total probability mass (or rates) of this choice. + ValueType totalMass; + + // The reward value associated with this choice. + ValueType choiceReward; + + // The labels that are associated with this choice. + boost::optional<LabelSet> choiceLabels; + }; + + template<typename ValueType, typename StateType> + std::ostream& operator<<(std::ostream& out, Choice<ValueType, StateType> const& choice); + + } +} + +#endif /* STORM_GENERATOR_CHOICE_H_ */ \ No newline at end of file diff --git a/src/generator/NextStateGenerator.h b/src/generator/NextStateGenerator.h new file mode 100644 index 000000000..1fdc38cfb --- /dev/null +++ b/src/generator/NextStateGenerator.h @@ -0,0 +1,27 @@ +#ifndef STORM_GENERATOR_NEXTSTATEGENERATOR_H_ +#define STORM_GENERATOR_NEXTSTATEGENERATOR_H_ + +#include <vector> +#include <cstdint> + +#include "src/storage/sparse/StateType.h" +#include "src/storage/BitVector.h" + +#include "src/generator/Choice.h" + +namespace storm { + namespace generator { + template<typename ValueType, typename StateType = uint32_t> + class NextStateGenerator { + public: + typedef storm::storage::BitVector InternalStateType; + typedef StateType (*StateToIdCallback)(InternalStateType const&); + + virtual std::vector<StateType> getInitialStates(StateToIdCallback stateToIdCallback) = 0; + virtual std::vector<Choice<ValueType>> expand(StateType const& state, StateToIdCallback stateToIdCallback) = 0; + virtual ValueType getStateReward(StateType const& state) = 0; + }; + } +} + +#endif \ No newline at end of file diff --git a/src/generator/PrismNextStateGenerator.cpp b/src/generator/PrismNextStateGenerator.cpp new file mode 100644 index 000000000..0acf4d8dd --- /dev/null +++ b/src/generator/PrismNextStateGenerator.cpp @@ -0,0 +1,22 @@ +#include "src/generator/PrismNextStateGenerator.h" + +namespace storm { + namespace generator { + + template<typename ValueType, typename StateType> + PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program) : program(program) { + // Intentionally left empty. + } + + template<typename ValueType, typename StateType> + std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::expand(StateType const& state, typename NextStateGenerator<ValueType, StateType>::StateToIdCallback stateToIdCallback) { + // TODO + } + + template<typename ValueType, typename StateType> + ValueType PrismNextStateGenerator<ValueType, StateType>::getStateReward(StateType const& state) { + // TODO + } + + } +} \ No newline at end of file diff --git a/src/generator/PrismNextStateGenerator.h b/src/generator/PrismNextStateGenerator.h new file mode 100644 index 000000000..1330d4420 --- /dev/null +++ b/src/generator/PrismNextStateGenerator.h @@ -0,0 +1,32 @@ +#ifndef STORM_GENERATOR_PRISMNEXTSTATEGENERATOR_H_ +#define STORM_GENERATOR_PRISMNEXTSTATEGENERATOR_H_ + +#include "src/generator/NextStateGenerator.h" + +#include "src/storage/prism/Program.h" + +namespace storm { + namespace generator { + + template<typename ValueType, typename StateType = uint32_t> + class PrismNextStateGenerator : public NextStateGenerator<ValueType, StateType> { + public: + typedef typename NextStateGenerator<ValueType, StateType>::StateToIdCallback StateToIdCallback; + + PrismNextStateGenerator(storm::prism::Program const& program); + + virtual std::vector<StateType> getInitialStates(StateToIdCallback stateToIdCallback) = 0; + virtual std::vector<Choice<ValueType>> expand(StateType const& state, StateToIdCallback stateToIdCallback) override; + virtual ValueType getStateReward(StateType const& state) override; + + private: + // The program used for the generation of next states. + storm::prism::Program program; + + + }; + + } +} + +#endif /* STORM_GENERATOR_PRISMNEXTSTATEGENERATOR_H_ */ \ No newline at end of file diff --git a/src/generator/prism/VariableInformation.cpp b/src/generator/prism/VariableInformation.cpp new file mode 100644 index 000000000..f648eda1b --- /dev/null +++ b/src/generator/prism/VariableInformation.cpp @@ -0,0 +1,44 @@ +#include "src/generator/prism/VariableInformation.h" + +#include "src/utility/macros.h" +#include "src/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace generator { + namespace prism { + + BooleanVariableInformation::BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset) : variable(variable), initialValue(initialValue), bitOffset(bitOffset) { + // Intentionally left empty. + } + + IntegerVariableInformation::IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth) : variable(variable), initialValue(initialValue), lowerBound(lowerBound), upperBound(upperBound), bitOffset(bitOffset), bitWidth(bitWidth) { + // Intentionally left empty. + } + + VariableInformation::VariableInformation(storm::expressions::ExpressionManager const& manager) : manager(manager) { + // Intentionally left empty. + } + + uint_fast64_t VariableInformation::getBitOffset(storm::expressions::Variable const& variable) const { + auto const& booleanIndex = booleanVariableToIndexMap.find(variable); + if (booleanIndex != booleanVariableToIndexMap.end()) { + return booleanVariables[booleanIndex->second].bitOffset; + } + auto const& integerIndex = integerVariableToIndexMap.find(variable); + if (integerIndex != integerVariableToIndexMap.end()) { + return integerVariables[integerIndex->second].bitOffset; + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit index of unknown variable."); + } + + uint_fast64_t VariableInformation::getBitWidth(storm::expressions::Variable const& variable) const { + auto const& integerIndex = integerVariableToIndexMap.find(variable); + if (integerIndex != integerVariableToIndexMap.end()) { + return integerVariables[integerIndex->second].bitWidth; + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit width of unknown variable."); + } + + } + } +} \ No newline at end of file diff --git a/src/generator/prism/VariableInformation.h b/src/generator/prism/VariableInformation.h new file mode 100644 index 000000000..56ac7bda2 --- /dev/null +++ b/src/generator/prism/VariableInformation.h @@ -0,0 +1,73 @@ +#ifndef STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ +#define STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ + +#include <vector> +#include <boost/container/flat_map.hpp> + +#include "src/storage/expressions/Variable.h" + +namespace storm { + namespace generator { + namespace prism { + + // A structure storing information about the boolean variables of the program. + struct BooleanVariableInformation { + BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset); + + // The boolean variable. + storm::expressions::Variable variable; + + // Its initial value. + bool initialValue; + + // Its bit offset in the compressed state. + uint_fast64_t bitOffset; + }; + + // A structure storing information about the integer variables of the program. + struct IntegerVariableInformation { + IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth); + + // The integer variable. + storm::expressions::Variable variable; + + // Its initial value. + int_fast64_t initialValue; + + // The lower bound of its range. + int_fast64_t lowerBound; + + // The upper bound of its range. + int_fast64_t upperBound; + + // Its bit offset in the compressed state. + uint_fast64_t bitOffset; + + // Its bit width in the compressed state. + uint_fast64_t bitWidth; + }; + + // A structure storing information about the used variables of the program. + struct VariableInformation { + VariableInformation(storm::expressions::ExpressionManager const& manager); + + // Provide methods to access the bit offset and width of variables in the compressed state. + uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const; + uint_fast64_t getBitWidth(storm::expressions::Variable const& variable) const; + + // The known boolean variables. + boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> booleanVariableToIndexMap; + std::vector<BooleanVariableInformation> booleanVariables; + + // The known integer variables. + boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> integerVariableToIndexMap; + std::vector<IntegerVariableInformation> integerVariables; + + storm::expressions::ExpressionManager const& manager; + }; + + } + } +} + +#endif /* STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ */ \ No newline at end of file diff --git a/src/storage/Distribution.cpp b/src/storage/Distribution.cpp index 50d794d01..516227277 100644 --- a/src/storage/Distribution.cpp +++ b/src/storage/Distribution.cpp @@ -14,13 +14,13 @@ namespace storm { namespace storage { - template<typename ValueType> - Distribution<ValueType>::Distribution() { + template<typename ValueType, typename StateType> + Distribution<ValueType, StateType>::Distribution() { // Intentionally left empty. } - template<typename ValueType> - bool Distribution<ValueType>::equals(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const { + template<typename ValueType, typename StateType> + bool Distribution<ValueType, StateType>::equals(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const { // We need to check equality by ourselves, because we need to account for epsilon differences. if (this->distribution.size() != other.distribution.size()) { return false; @@ -42,8 +42,8 @@ namespace storm { return true; } - template<typename ValueType> - void Distribution<ValueType>::addProbability(storm::storage::sparse::state_type const& state, ValueType const& probability) { + template<typename ValueType, typename StateType> + void Distribution<ValueType, StateType>::addProbability(StateType const& state, ValueType const& probability) { auto it = this->distribution.find(state); if (it == this->distribution.end()) { this->distribution.emplace_hint(it, state, probability); @@ -52,8 +52,8 @@ namespace storm { } } - template<typename ValueType> - void Distribution<ValueType>::removeProbability(storm::storage::sparse::state_type const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) { + template<typename ValueType, typename StateType> + void Distribution<ValueType, StateType>::removeProbability(StateType const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) { auto it = this->distribution.find(state); STORM_LOG_ASSERT(it != this->distribution.end(), "Cannot remove probability, because the state is not in the support of the distribution."); it->second -= probability; @@ -62,34 +62,34 @@ namespace storm { } } - template<typename ValueType> - void Distribution<ValueType>::shiftProbability(storm::storage::sparse::state_type const& fromState, storm::storage::sparse::state_type const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) { + template<typename ValueType, typename StateType> + void Distribution<ValueType, StateType>::shiftProbability(StateType const& fromState, StateType const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) { removeProbability(fromState, probability, comparator); addProbability(toState, probability); } - template<typename ValueType> - typename Distribution<ValueType>::iterator Distribution<ValueType>::begin() { + template<typename ValueType, typename StateType> + typename Distribution<ValueType, StateType>::iterator Distribution<ValueType, StateType>::begin() { return this->distribution.begin(); } - template<typename ValueType> - typename Distribution<ValueType>::const_iterator Distribution<ValueType>::begin() const { + template<typename ValueType, typename StateType> + typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::begin() const { return this->distribution.begin(); } - template<typename ValueType> - typename Distribution<ValueType>::iterator Distribution<ValueType>::end() { + template<typename ValueType, typename StateType> + typename Distribution<ValueType, StateType>::iterator Distribution<ValueType, StateType>::end() { return this->distribution.end(); } - template<typename ValueType> - typename Distribution<ValueType>::const_iterator Distribution<ValueType>::end() const { + template<typename ValueType, typename StateType> + typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::end() const { return this->distribution.end(); } - template<typename ValueType> - void Distribution<ValueType>::scale(storm::storage::sparse::state_type const& state) { + template<typename ValueType, typename StateType> + void Distribution<ValueType, StateType>::scale(StateType const& state) { auto probabilityIterator = this->distribution.find(state); if (probabilityIterator != this->distribution.end()) { ValueType scaleValue = storm::utility::one<ValueType>() / probabilityIterator->second; @@ -101,13 +101,13 @@ namespace storm { } } - template<typename ValueType> - std::size_t Distribution<ValueType>::size() const { + template<typename ValueType, typename StateType> + std::size_t Distribution<ValueType, StateType>::size() const { return this->distribution.size(); } - template<typename ValueType> - std::ostream& operator<<(std::ostream& out, Distribution<ValueType> const& distribution) { + template<typename ValueType, typename StateType> + std::ostream& operator<<(std::ostream& out, Distribution<ValueType, StateType> const& distribution) { out << "{"; for (auto const& entry : distribution) { out << "[" << entry.second << ": " << entry.first << "], "; @@ -117,8 +117,8 @@ namespace storm { return out; } - template<typename ValueType> - bool Distribution<ValueType>::less(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const { + template<typename ValueType, typename StateType> + bool Distribution<ValueType, StateType>::less(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const { if (this->size() != other.size()) { return this->size() < other.size(); } diff --git a/src/storage/Distribution.h b/src/storage/Distribution.h index 9d3276941..39e6eb6f9 100644 --- a/src/storage/Distribution.h +++ b/src/storage/Distribution.h @@ -17,10 +17,10 @@ namespace storm { namespace storage { - template<typename ValueType> + template<typename ValueType, typename StateType=storm::storage::sparse::state_type> class Distribution { public: - typedef boost::container::flat_map<storm::storage::sparse::state_type, ValueType> container_type; + typedef boost::container::flat_map<StateType, ValueType> container_type; typedef typename container_type::iterator iterator; typedef typename container_type::const_iterator const_iterator; @@ -51,7 +51,7 @@ namespace storm { * @param state The state to which to assign the probability. * @param probability The probability to assign. */ - void addProbability(storm::storage::sparse::state_type const& state, ValueType const& probability); + void addProbability(StateType const& state, ValueType const& probability); /*! * Removes the given probability mass of going to the given state. @@ -61,7 +61,7 @@ namespace storm { * @param comparator A comparator that is used to determine if the remaining probability is zero. If so, the * entry is removed. */ - void removeProbability(storm::storage::sparse::state_type const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>()); + void removeProbability(StateType const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>()); /*! * Removes the probability mass from one state and adds it to another. @@ -72,7 +72,7 @@ namespace storm { * @param comparator A comparator that is used to determine if the remaining probability is zero. If so, the * entry is removed. */ - void shiftProbability(storm::storage::sparse::state_type const& fromState, storm::storage::sparse::state_type const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>()); + void shiftProbability(StateType const& fromState, StateType const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>()); /*! * Retrieves an iterator to the elements in this distribution. @@ -109,7 +109,7 @@ namespace storm { * * @param state The state whose associated probability is used to scale the distribution. */ - void scale(storm::storage::sparse::state_type const& state); + void scale(StateType const& state); /*! * Retrieves the size of the distribution, i.e. the size of the support set. From 8a0bd32b553864a2220e05c1ff089f664ff0f54b Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 23 Feb 2016 22:31:01 +0100 Subject: [PATCH 02/33] tearing apart explicit model builder and 'next-state generation' Former-commit-id: 2ccda8d931c279bb7b9359f901ea1980e08575b1 --- src/CMakeLists.txt | 4 +- src/builder/ExplicitPrismModelBuilder.cpp | 437 +++++--------------- src/builder/ExplicitPrismModelBuilder.h | 98 ++--- src/generator/Choice.cpp | 4 +- src/generator/Choice.h | 4 +- src/generator/NextStateGenerator.h | 10 +- src/generator/PrismNextStateGenerator.cpp | 249 ++++++++++- src/generator/PrismNextStateGenerator.h | 92 ++++- src/generator/VariableInformation.cpp | 42 ++ src/generator/VariableInformation.h | 71 ++++ src/generator/prism/VariableInformation.cpp | 44 -- src/generator/prism/VariableInformation.h | 73 ---- src/storage/prism/Program.cpp | 4 + src/storage/prism/Program.h | 12 + 14 files changed, 607 insertions(+), 537 deletions(-) create mode 100644 src/generator/VariableInformation.cpp create mode 100644 src/generator/VariableInformation.h delete mode 100644 src/generator/prism/VariableInformation.cpp delete mode 100644 src/generator/prism/VariableInformation.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a5832d87..7587a3f22 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,8 +11,7 @@ file(GLOB_RECURSE STORM_SOURCES_CLI ${PROJECT_SOURCE_DIR}/src/cli/*.cpp) file(GLOB_RECURSE STORM_MAIN_FILE ${PROJECT_SOURCE_DIR}/src/storm.cpp) file(GLOB_RECURSE STORM_ADAPTERS_FILES ${PROJECT_SOURCE_DIR}/src/adapters/*.h ${PROJECT_SOURCE_DIR}/src/adapters/*.cpp) file(GLOB_RECURSE STORM_BUILDER_FILES ${PROJECT_SOURCE_DIR}/src/builder/*.h ${PROJECT_SOURCE_DIR}/src/builder/*.cpp) -file(GLOB STORM_GENERATOR_FILES ${PROJECT_SOURCE_DIR}/src/generator/*.h ${PROJECT_SOURCE_DIR}/src/generator/*.cpp) -file(GLOB_RECURSE STORM_GENERATOR_PRISM_FILES ${PROJECT_SOURCE_DIR}/src/generator/prism/*.h ${PROJECT_SOURCE_DIR}/src/generator/prism/*.cpp) +file(GLOB_RECURSE STORM_GENERATOR_FILES ${PROJECT_SOURCE_DIR}/src/generator/*.h ${PROJECT_SOURCE_DIR}/src/generator/*.cpp) file(GLOB_RECURSE STORM_CLI_FILES ${PROJECT_SOURCE_DIR}/src/cli/*.h ${PROJECT_SOURCE_DIR}/src/cli/*.cpp) file(GLOB_RECURSE STORM_EXCEPTIONS_FILES ${PROJECT_SOURCE_DIR}/src/exceptions/*.h ${PROJECT_SOURCE_DIR}/src/exceptions/*.cpp) file(GLOB_RECURSE STORM_LOGIC_FILES ${PROJECT_SOURCE_DIR}/src/logic/*.h ${PROJECT_SOURCE_DIR}/src/logic/*.cpp) @@ -60,7 +59,6 @@ source_group(main FILES ${STORM_MAIN_FILE}) source_group(adapters FILES ${STORM_ADAPTERS_FILES}) source_group(builder FILES ${STORM_BUILDER_FILES}) source_group(generator FILES ${STORM_GENERATOR_FILES}) -source_group(generator\\prism FILES ${STORM_GENERATOR_PRISM_FILES}) source_group(cli FILES ${STORM_CLI_FILES}) source_group(exceptions FILES ${STORM_EXCEPTIONS_FILES}) source_group(logic FILES ${STORM_LOGIC_FILES}) diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp index 19b115c6e..039048111 100644 --- a/src/builder/ExplicitPrismModelBuilder.cpp +++ b/src/builder/ExplicitPrismModelBuilder.cpp @@ -66,33 +66,33 @@ namespace storm { storm::storage::SparseMatrixBuilder<ValueType> transitionRewardMatrixBuilder; }; - template <typename ValueType, typename RewardModelType, typename IndexType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::StateInformation::StateInformation(uint_fast64_t numberOfStates) : valuations(numberOfStates) { + template <typename ValueType, typename RewardModelType, typename StateType> + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::StateInformation::StateInformation(uint_fast64_t numberOfStates) : valuations(numberOfStates) { // Intentionally left empty. } - template <typename ValueType, typename RewardModelType, typename IndexType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::InternalStateInformation::InternalStateInformation(uint64_t bitsPerState) : stateStorage(bitsPerState, 10000000), bitsPerState(bitsPerState), reachableStates() { + template <typename ValueType, typename RewardModelType, typename StateType> + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::InternalStateInformation::InternalStateInformation(uint64_t bitsPerState) : stateStorage(bitsPerState, 10000000), bitsPerState(bitsPerState), numberOfStates() { // Intentionally left empty. } - template <typename ValueType, typename RewardModelType, typename IndexType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), rewardModels(), choiceLabeling() { + template <typename ValueType, typename RewardModelType, typename StateType> + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), rewardModels(), choiceLabeling() { // Intentionally left empty. } - template <typename ValueType, typename RewardModelType, typename IndexType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::Options() : buildCommandLabels(false), buildAllRewardModels(true), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(true), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() { + template <typename ValueType, typename RewardModelType, typename StateType> + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options() : buildCommandLabels(false), buildAllRewardModels(true), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(true), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() { // Intentionally left empty. } - template <typename ValueType, typename RewardModelType, typename IndexType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::Options(storm::logic::Formula const& formula) : buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(std::set<std::string>()), expressionLabels(std::vector<storm::expressions::Expression>()), terminalStates(), negatedTerminalStates() { + template <typename ValueType, typename RewardModelType, typename StateType> + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(storm::logic::Formula const& formula) : buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(std::set<std::string>()), expressionLabels(std::vector<storm::expressions::Expression>()), terminalStates(), negatedTerminalStates() { this->preserveFormula(formula); } - template <typename ValueType, typename RewardModelType, typename IndexType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::Options(std::vector<std::shared_ptr<const storm::logic::Formula>> const& formulas) : buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() { + template <typename ValueType, typename RewardModelType, typename StateType> + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(std::vector<std::shared_ptr<const storm::logic::Formula>> const& formulas) : buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() { if (formulas.empty()) { this->buildAllRewardModels = true; this->buildAllLabels = true; @@ -106,8 +106,8 @@ namespace storm { } } - template <typename ValueType, typename RewardModelType, typename IndexType> - void ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::setTerminalStatesFromFormula(storm::logic::Formula const& formula) { + template <typename ValueType, typename RewardModelType, typename StateType> + void ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::setTerminalStatesFromFormula(storm::logic::Formula const& formula) { if (formula.isAtomicExpressionFormula()) { terminalStates = formula.asAtomicExpressionFormula().getExpression(); } else if (formula.isAtomicLabelFormula()) { @@ -136,8 +136,8 @@ namespace storm { } } - template <typename ValueType, typename RewardModelType, typename IndexType> - void ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::preserveFormula(storm::logic::Formula const& formula) { + template <typename ValueType, typename RewardModelType, typename StateType> + void ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::preserveFormula(storm::logic::Formula const& formula) { // If we already had terminal states, we need to erase them. if (terminalStates) { terminalStates.reset(); @@ -174,105 +174,108 @@ namespace storm { } } - template <typename ValueType, typename RewardModelType, typename IndexType> - void ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::addConstantDefinitionsFromString(storm::prism::Program const& program, std::string const& constantDefinitionString) { + template <typename ValueType, typename RewardModelType, typename StateType> + void ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::addConstantDefinitionsFromString(storm::prism::Program const& program, std::string const& constantDefinitionString) { constantDefinitions = storm::utility::prism::parseConstantDefinitionString(program, constantDefinitionString); } - template <typename ValueType, typename RewardModelType, typename IndexType> - typename ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::StateInformation const& ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getStateInformation() const { - STORM_LOG_THROW(static_cast<bool>(stateInformation), storm::exceptions::InvalidOperationException, "The state information was not properly build."); - return stateInformation.get(); - } - - template <typename ValueType, typename RewardModelType, typename IndexType> - storm::prism::Program const& ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getTranslatedProgram() const { - return preparedProgram.get(); - } - - template <typename ValueType, typename RewardModelType, typename IndexType> - std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::translateProgram(storm::prism::Program program, Options const& options) { + template <typename ValueType, typename RewardModelType, typename StateType> + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ExplicitPrismModelBuilder(storm::prism::Program const& program, Options const& options) : options(options), program(program) { // Start by defining the undefined constants in the model. if (options.constantDefinitions) { - preparedProgram = program.defineUndefinedConstants(options.constantDefinitions.get()); + this->program = program.defineUndefinedConstants(options.constantDefinitions.get()); } else { - preparedProgram = program; + this->program = program; } - + // If the program still contains undefined constants and we are not in a parametric setting, assemble an appropriate error message. #ifdef STORM_HAVE_CARL // If the program either has undefined constants or we are building a parametric model, but the parameters // not only appear in the probabilities, we re - if (!std::is_same<ValueType, storm::RationalFunction>::value && preparedProgram->hasUndefinedConstants()) { + if (!std::is_same<ValueType, storm::RationalFunction>::value && this->program.hasUndefinedConstants()) { #else - if (preparedProgram->hasUndefinedConstants()) { + if (this->program->hasUndefinedConstants()) { #endif - std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = preparedProgram->getUndefinedConstants(); - std::stringstream stream; - bool printComma = false; - for (auto const& constant : undefinedConstants) { - if (printComma) { - stream << ", "; - } else { - printComma = true; + std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = this->program.getUndefinedConstants(); + std::stringstream stream; + bool printComma = false; + for (auto const& constant : undefinedConstants) { + if (printComma) { + stream << ", "; + } else { + printComma = true; + } + stream << constant.get().getName() << " (" << constant.get().getType() << ")"; } - stream << constant.get().getName() << " (" << constant.get().getType() << ")"; - } - stream << "."; - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str()); + stream << "."; + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str()); #ifdef STORM_HAVE_CARL - } else if (std::is_same<ValueType, storm::RationalFunction>::value && !preparedProgram->hasUndefinedConstantsOnlyInUpdateProbabilitiesAndRewards()) { - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The program contains undefined constants that appear in some places other than update probabilities and reward value expressions, which is not admitted."); + } else if (std::is_same<ValueType, storm::RationalFunction>::value && !this->program.hasUndefinedConstantsOnlyInUpdateProbabilitiesAndRewards()) { + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The program contains undefined constants that appear in some places other than update probabilities and reward value expressions, which is not admitted."); #endif - } - - // If the set of labels we are supposed to built is restricted, we need to remove the other labels from the program. - if (options.labelsToBuild) { - if (!options.buildAllLabels) { - preparedProgram->filterLabels(options.labelsToBuild.get()); } - } - - // If we need to build labels for expressions that may appear in some formula, we need to add appropriate - // labels to the program. - if (options.expressionLabels) { - std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = preparedProgram->getConstantsSubstitution(); - - for (auto const& expression : options.expressionLabels.get()) { - std::stringstream stream; - stream << expression.substitute(constantsSubstitution); - std::string name = stream.str(); - if (!preparedProgram->hasLabel(name)) { - preparedProgram->addLabel(name, expression); + + // If the set of labels we are supposed to built is restricted, we need to remove the other labels from the program. + if (options.labelsToBuild) { + if (!options.buildAllLabels) { + this->program.filterLabels(options.labelsToBuild.get()); + } + } + + // If we need to build labels for expressions that may appear in some formula, we need to add appropriate + // labels to the program. + if (options.expressionLabels) { + std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = this->program.getConstantsSubstitution(); + + for (auto const& expression : options.expressionLabels.get()) { + std::stringstream stream; + stream << expression.substitute(constantsSubstitution); + std::string name = stream.str(); + if (!this->program.hasLabel(name)) { + this->program.addLabel(name, expression); + } } } - } - - // Now that the program is fixed, we we need to substitute all constants with their concrete value. - preparedProgram = preparedProgram->substituteConstants(); - - STORM_LOG_DEBUG("Building representation of program:" << std::endl << *preparedProgram << std::endl); + + // Now that the program is fixed, we we need to substitute all constants with their concrete value. + this->program = program.substituteConstants(); + } + + template <typename ValueType, typename RewardModelType, typename StateType> + typename ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::StateInformation const& ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getStateInformation() const { + STORM_LOG_THROW(static_cast<bool>(stateInformation), storm::exceptions::InvalidOperationException, "The state information was not properly build."); + return stateInformation.get(); + } + + template <typename ValueType, typename RewardModelType, typename StateType> + storm::prism::Program const& ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getTranslatedProgram() const { + return program; + } + + template <typename ValueType, typename RewardModelType, typename StateType> + std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::translate() { + STORM_LOG_DEBUG("Building representation of program:" << std::endl << *program << std::endl); // Select the appropriate reward models (after the constants have been substituted). std::vector<std::reference_wrapper<storm::prism::RewardModel const>> selectedRewardModels; // First, we make sure that all selected reward models actually exist. for (auto const& rewardModelName : options.rewardModelsToBuild) { - STORM_LOG_THROW(rewardModelName.empty() || preparedProgram->hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'."); + STORM_LOG_THROW(rewardModelName.empty() || program.hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'."); } - for (auto const& rewardModel : preparedProgram->getRewardModels()) { + for (auto const& rewardModel : program.getRewardModels()) { if (options.buildAllRewardModels || options.rewardModelsToBuild.find(rewardModel.getName()) != options.rewardModelsToBuild.end()) { selectedRewardModels.push_back(rewardModel); } } // If no reward model was selected until now and a referenced reward model appears to be unique, we build // the only existing reward model (given that no explicit name was given for the referenced reward model). - if (selectedRewardModels.empty() && preparedProgram->getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") { - selectedRewardModels.push_back(preparedProgram->getRewardModel(0)); + if (selectedRewardModels.empty() && program.getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") { + selectedRewardModels.push_back(program.getRewardModel(0)); } - ModelComponents modelComponents = buildModelComponents(*preparedProgram, selectedRewardModels, options); + ModelComponents modelComponents = buildModelComponents(*program, selectedRewardModels, options); std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> result; switch (program.getModelType()) { @@ -292,19 +295,9 @@ namespace storm { return result; } - - template <typename ValueType, typename RewardModelType, typename IndexType> - void ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::unpackStateIntoEvaluator(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator) { - for (auto const& booleanVariable : variableInformation.booleanVariables) { - evaluator.setBooleanValue(booleanVariable.variable, currentState.get(booleanVariable.bitOffset)); - } - for (auto const& integerVariable : variableInformation.integerVariables) { - evaluator.setIntegerValue(integerVariable.variable, currentState.getAsInt(integerVariable.bitOffset, integerVariable.bitWidth) + integerVariable.lowerBound); - } - } - - template <typename ValueType, typename RewardModelType, typename IndexType> - storm::expressions::SimpleValuation ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::unpackStateIntoValuation(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation) { + + template <typename ValueType, typename RewardModelType, typename StateType> + storm::expressions::SimpleValuation ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::unpackStateIntoValuation(storm::storage::BitVector const& currentState) { storm::expressions::SimpleValuation result(variableInformation.manager.getSharedPointer()); for (auto const& booleanVariable : variableInformation.booleanVariables) { result.setBooleanValue(booleanVariable.variable, currentState.get(booleanVariable.bitOffset)); @@ -315,254 +308,26 @@ namespace storm { return result; } - template <typename ValueType, typename RewardModelType, typename IndexType> - typename ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::CompressedState ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, storm::prism::Update const& update, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator) { - return applyUpdate(variableInformation, state, state, update, evaluator); - } - - template <typename ValueType, typename RewardModelType, typename IndexType> - typename ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::CompressedState ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, CompressedState const& baseState, storm::prism::Update const& update, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator) { - CompressedState newState(state); - - auto assignmentIt = update.getAssignments().begin(); - auto assignmentIte = update.getAssignments().end(); - - // Iterate over all boolean assignments and carry them out. - auto boolIt = variableInformation.booleanVariables.begin(); - for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasBooleanType(); ++assignmentIt) { - while (assignmentIt->getVariable() != boolIt->variable) { - ++boolIt; - } - newState.set(boolIt->bitOffset, evaluator.asBool(assignmentIt->getExpression())); - } - - // Iterate over all integer assignments and carry them out. - auto integerIt = variableInformation.integerVariables.begin(); - for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasIntegerType(); ++assignmentIt) { - while (assignmentIt->getVariable() != integerIt->variable) { - ++integerIt; - } - int_fast64_t assignedValue = evaluator.asInt(assignmentIt->getExpression()); - STORM_LOG_THROW(assignedValue <= integerIt->upperBound, storm::exceptions::WrongFormatException, "The update " << update << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getVariableName() << "'."); - newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, assignedValue - integerIt->lowerBound); - STORM_LOG_ASSERT(static_cast<int_fast64_t>(newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote " << assignedValue << ")."); - } - - // Check that we processed all assignments. - STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed."); - - return newState; - } - - template <typename ValueType, typename RewardModelType, typename IndexType> - IndexType ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getOrAddStateIndex(CompressedState const& state, InternalStateInformation& internalStateInformation, std::queue<storm::storage::BitVector>& stateQueue) { + template <typename ValueType, typename RewardModelType, typename StateType> + StateType ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex(CompressedState const& state) { uint32_t newIndex = internalStateInformation.reachableStates.size(); // Check, if the state was already registered. std::pair<uint32_t, std::size_t> actualIndexBucketPair = internalStateInformation.stateStorage.findOrAddAndGetBucket(state, newIndex); if (actualIndexBucketPair.first == newIndex) { - stateQueue.push(state); - internalStateInformation.reachableStates.push_back(state); + statesToExplore.push(state); + ++internalStateInformation.numberOfStates; } return actualIndexBucketPair.first; } - - template <typename ValueType, typename RewardModelType, typename IndexType> - boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getActiveCommandsByActionIndex(storm::prism::Program const& program,storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, uint_fast64_t const& actionIndex) { - boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> result((std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>())); - - // Iterate over all modules. - for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) { - storm::prism::Module const& module = program.getModule(i); - - // If the module has no command labeled with the given action, we can skip this module. - if (!module.hasActionIndex(actionIndex)) { - continue; - } - - std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex); - - // If the module contains the action, but there is no command in the module that is labeled with - // this action, we don't have any feasible command combinations. - if (commandIndices.empty()) { - return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>(); - } - - std::vector<std::reference_wrapper<storm::prism::Command const>> commands; - - // Look up commands by their indices and add them if the guard evaluates to true in the given state. - for (uint_fast64_t commandIndex : commandIndices) { - storm::prism::Command const& command = module.getCommand(commandIndex); - if (evaluator.asBool(command.getGuardExpression())) { - commands.push_back(command); - } - } - - // If there was no enabled command although the module has some command with the required action label, - // we must not return anything. - if (commands.size() == 0) { - return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>(); - } - - result.get().push_back(std::move(commands)); - } - - return result; - } - - template <typename ValueType, typename RewardModelType, typename IndexType> - std::vector<Choice<ValueType>> ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getUnlabeledTransitions(storm::prism::Program const& program, bool discreteTimeModel, InternalStateInformation& internalStateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, bool choiceLabeling, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, std::queue<storm::storage::BitVector>& stateQueue, storm::utility::ConstantsComparator<ValueType> const& comparator) { - std::vector<Choice<ValueType>> result; - - // Iterate over all modules. - for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) { - storm::prism::Module const& module = program.getModule(i); - - // Iterate over all commands. - for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) { - storm::prism::Command const& command = module.getCommand(j); - - // Only consider unlabeled commands. - if (command.isLabeled()) continue; - - // Skip the command, if it is not enabled. - if (!evaluator.asBool(command.getGuardExpression())) { - continue; - } - - result.push_back(Choice<ValueType>(0, choiceLabeling)); - Choice<ValueType>& choice = result.back(); - - // Remember the command labels only if we were asked to. - if (choiceLabeling) { - choice.addChoiceLabel(command.getGlobalIndex()); - } - - // Iterate over all updates of the current command. - ValueType probabilitySum = storm::utility::zero<ValueType>(); - for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) { - storm::prism::Update const& update = command.getUpdate(k); - - // Obtain target state index and add it to the list of known states. If it has not yet been - // seen, we also add it to the set of states that have yet to be explored. - uint32_t stateIndex = getOrAddStateIndex(applyUpdate(variableInformation, currentState, update, evaluator), internalStateInformation, stateQueue); - - // Update the choice by adding the probability/target state to it. - ValueType probability = evaluator.asRational(update.getLikelihoodExpression()); - choice.addProbability(stateIndex, probability); - probabilitySum += probability; - } - - // Check that the resulting distribution is in fact a distribution. - STORM_LOG_THROW(!discreteTimeModel || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for command '" << command << "' (actually sum to " << probabilitySum << ")."); - } - } - - return result; - } - - template <typename ValueType, typename RewardModelType, typename IndexType> - std::vector<Choice<ValueType>> ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getLabeledTransitions(storm::prism::Program const& program, bool discreteTimeModel, InternalStateInformation& internalStateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, bool choiceLabeling, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, std::queue<storm::storage::BitVector>& stateQueue, storm::utility::ConstantsComparator<ValueType> const& comparator) { - std::vector<Choice<ValueType>> result; - - for (uint_fast64_t actionIndex : program.getSynchronizingActionIndices()) { - boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> optionalActiveCommandLists = getActiveCommandsByActionIndex(program, evaluator, actionIndex); - - // Only process this action label, if there is at least one feasible solution. - if (optionalActiveCommandLists) { - std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> const& activeCommandList = optionalActiveCommandLists.get(); - std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> iteratorList(activeCommandList.size()); - - // Initialize the list of iterators. - for (size_t i = 0; i < activeCommandList.size(); ++i) { - iteratorList[i] = activeCommandList[i].cbegin(); - } - - // As long as there is one feasible combination of commands, keep on expanding it. - bool done = false; - while (!done) { - std::unordered_map<CompressedState, ValueType>* currentTargetStates = new std::unordered_map<CompressedState, ValueType>(); - std::unordered_map<CompressedState, ValueType>* newTargetStates = new std::unordered_map<CompressedState, ValueType>(); - currentTargetStates->emplace(currentState, storm::utility::one<ValueType>()); - - for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { - storm::prism::Command const& command = *iteratorList[i]; - - for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) { - storm::prism::Update const& update = command.getUpdate(j); - - for (auto const& stateProbabilityPair : *currentTargetStates) { - // Compute the new state under the current update and add it to the set of new target states. - CompressedState newTargetState = applyUpdate(variableInformation, stateProbabilityPair.first, currentState, update, evaluator); - newTargetStates->emplace(newTargetState, stateProbabilityPair.second * evaluator.asRational(update.getLikelihoodExpression())); - } - } - - // If there is one more command to come, shift the target states one time step back. - if (i < iteratorList.size() - 1) { - delete currentTargetStates; - currentTargetStates = newTargetStates; - newTargetStates = new std::unordered_map<CompressedState, ValueType>(); - } - } - - // At this point, we applied all commands of the current command combination and newTargetStates - // contains all target states and their respective probabilities. That means we are now ready to - // add the choice to the list of transitions. - result.push_back(Choice<ValueType>(actionIndex, choiceLabeling)); - - // Now create the actual distribution. - Choice<ValueType>& choice = result.back(); - - // Remember the command labels only if we were asked to. - if (choiceLabeling) { - // Add the labels of all commands to this choice. - for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { - choice.addChoiceLabel(iteratorList[i]->get().getGlobalIndex()); - } - } - - ValueType probabilitySum = storm::utility::zero<ValueType>(); - for (auto const& stateProbabilityPair : *newTargetStates) { - uint32_t actualIndex = getOrAddStateIndex(stateProbabilityPair.first, internalStateInformation, stateQueue); - choice.addProbability(actualIndex, stateProbabilityPair.second); - probabilitySum += stateProbabilityPair.second; - } - - // Check that the resulting distribution is in fact a distribution. - STORM_LOG_THROW(!discreteTimeModel || !comparator.isConstant(probabilitySum) || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not some to one for some command (actually sum to " << probabilitySum << ")."); - - // Dispose of the temporary maps. - delete currentTargetStates; - delete newTargetStates; - - // Now, check whether there is one more command combination to consider. - bool movedIterator = false; - for (int_fast64_t j = iteratorList.size() - 1; j >= 0; --j) { - ++iteratorList[j]; - if (iteratorList[j] != activeCommandList[j].end()) { - movedIterator = true; - } else { - // Reset the iterator to the beginning of the list. - iteratorList[j] = activeCommandList[j].begin(); - } - } - - done = !movedIterator; - } - } - } - - return result; - } - template <typename ValueType, typename RewardModelType, typename IndexType> - boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::buildMatrices(storm::prism::Program const& program, VariableInformation const& variableInformation, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, InternalStateInformation& internalStateInformation, bool commandLabels, bool deterministicModel, bool discreteTimeModel, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression) { + template <typename ValueType, typename RewardModelType, typename StateType> + boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildMatrices(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, InternalStateInformation& internalStateInformation, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression) { // Create choice labels, if requested, boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> choiceLabels; - if (commandLabels) { + if (options.buildCommandLabels) { choiceLabels = std::vector<boost::container::flat_set<uint_fast64_t>>(); } @@ -606,7 +371,7 @@ namespace storm { // Get the current state and unpack it. storm::storage::BitVector currentState = stateQueue.front(); stateQueue.pop(); - IndexType stateIndex = internalStateInformation.stateStorage.getValue(currentState); + StateType stateIndex = internalStateInformation.stateStorage.getValue(currentState); STORM_LOG_TRACE("Exploring state with id " << stateIndex << "."); unpackStateIntoEvaluator(currentState, variableInformation, evaluator); @@ -615,11 +380,7 @@ namespace storm { std::vector<Choice<ValueType>> allLabeledChoices; bool deadlockOnPurpose = false; if (terminalExpression && evaluator.asBool(terminalExpression.get())) { - //std::cout << unpackStateIntoValuation(currentState, variableInformation).toString(true) << std::endl; - //allUnlabeledChoices = getUnlabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator); - //allLabeledChoices = getLabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator); - - // Nothing to do in this case. + // Nothing to do in this case. deadlockOnPurpose = true; } else { // Retrieve all choices for the current state. @@ -886,8 +647,8 @@ namespace storm { return choiceLabels; } - template <typename ValueType, typename RewardModelType, typename IndexType> - typename ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::ModelComponents ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::buildModelComponents(storm::prism::Program const& program, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, Options const& options) { + template <typename ValueType, typename RewardModelType, typename StateType> + typename ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ModelComponents ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildModelComponents(storm::prism::Program const& program, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, Options const& options) { ModelComponents modelComponents; uint_fast64_t bitOffset = 0; @@ -991,8 +752,8 @@ namespace storm { return modelComponents; } - template <typename ValueType, typename RewardModelType, typename IndexType> - storm::models::sparse::StateLabeling ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::buildStateLabeling(storm::prism::Program const& program, VariableInformation const& variableInformation, InternalStateInformation const& internalStateInformation) { + template <typename ValueType, typename RewardModelType, typename StateType> + storm::models::sparse::StateLabeling ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildStateLabeling(storm::prism::Program const& program, VariableInformation const& variableInformation, InternalStateInformation const& internalStateInformation) { storm::expressions::ExpressionEvaluator<ValueType> evaluator(program.getManager()); std::vector<storm::prism::Label> const& labels = program.getLabels(); diff --git a/src/builder/ExplicitPrismModelBuilder.h b/src/builder/ExplicitPrismModelBuilder.h index 9bd62ad2b..5e4f5b2c5 100644 --- a/src/builder/ExplicitPrismModelBuilder.h +++ b/src/builder/ExplicitPrismModelBuilder.h @@ -22,9 +22,11 @@ #include "src/storage/SparseMatrix.h" #include "src/settings/SettingsManager.h" -#include "src/utility/constants.h" + #include "src/utility/prism.h" +#include "src/generator/VariableInformation.h" + namespace storm { namespace utility { template<typename ValueType> class ConstantsComparator; @@ -37,7 +39,7 @@ namespace storm { // Forward-declare classes. template <typename ValueType> struct RewardModelBuilder; - template<typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>, typename IndexType = uint32_t> + template<typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>, typename StateType = uint32_t> class ExplicitPrismModelBuilder { public: typedef storm::storage::BitVector CompressedState; @@ -47,16 +49,16 @@ namespace storm { InternalStateInformation(uint64_t bitsPerState); // This member stores all the states and maps them to their unique indices. - storm::storage::BitVectorHashMap<IndexType> stateStorage; + storm::storage::BitVectorHashMap<StateType> stateStorage; // A list of initial states in terms of their global indices. - std::vector<IndexType> initialStateIndices; + std::vector<StateType> initialStateIndices; // The number of bits of each state. uint64_t bitsPerState; - // A list of reachable states as indices in the stateToIndexMap. - std::vector<storm::storage::BitVector> reachableStates; + // The number of states that were found in the exploration so far. + uint_fast64_t numberOfStates; }; // A structure holding information about the reachable state space that can be retrieved from the outside. @@ -174,6 +176,13 @@ namespace storm { boost::optional<boost::variant<storm::expressions::Expression, std::string>> negatedTerminalStates; }; + /*! + * Creates a builder for the given program. + * + * @param program The program to build. + */ + ExplicitPrismModelBuilder(storm::prism::Program const& program, Options const& options = Options()); + /*! * Convert the program given at construction time to an abstract model. The type of the model is the one * specified in the program. The given reward model name selects the rewards that the model will contain. @@ -184,7 +193,7 @@ namespace storm { * @param rewardModel The reward model that is to be built. * @return The explicit model that was given by the probabilistic program. */ - std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> translateProgram(storm::prism::Program program, Options const& options = Options()); + std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> translate(); /*! * If requested in the options, information about the variable valuations in the reachable states can be @@ -195,39 +204,14 @@ namespace storm { StateInformation const& getStateInformation() const; /*! - * Retrieves the program that was actually translated (i.e. including constant substitutions etc.). Note - * that this function may only be called after a succesful translation. + * Retrieves the program that was actually translated (i.e. including constant substitutions etc.). * * @return The translated program. */ storm::prism::Program const& getTranslatedProgram() const; private: - static void unpackStateIntoEvaluator(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator); - - static storm::expressions::SimpleValuation unpackStateIntoValuation(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation); - - /*! - * Applies an update to the given state and returns the resulting new state object. This methods does not - * modify the given state but returns a new one. - * - * @params state The state to which to apply the update. - * @params update The update to apply. - * @return The resulting state. - */ - static CompressedState applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, storm::prism::Update const& update, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator); - - /*! - * Applies an update to the given state and returns the resulting new state object. The update is evaluated - * over the variable values of the given base state. This methods does not modify the given state but - * returns a new one. - * - * @param state The state to which to apply the update. - * @param baseState The state used for evaluating the update. - * @param update The update to apply. - * @return The resulting state. - */ - static CompressedState applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, CompressedState const& baseState, storm::prism::Update const& update, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator); + storm::expressions::SimpleValuation unpackStateIntoValuation(storm::storage::BitVector const& currentState); /*! * Retrieves the state id of the given state. If the state has not been encountered yet, it will be added to @@ -239,29 +223,8 @@ namespace storm { * @param internalStateInformation The information about the already explored part of the reachable state space. * @return A pair indicating whether the state was already discovered before and the state id of the state. */ - static IndexType getOrAddStateIndex(CompressedState const& state, InternalStateInformation& internalStateInformation, std::queue<storm::storage::BitVector>& stateQueue); + StateType getOrAddStateIndex(CompressedState const& state); - /*! - * Retrieves all commands that are labeled with the given label and enabled in the given state, grouped by - * modules. - * - * This function will iterate over all modules and retrieve all commands that are labeled with the given - * action and active (i.e. enabled) in the current state. The result is a list of lists of commands in which - * the inner lists contain all commands of exactly one module. If a module does not have *any* (including - * disabled) commands, there will not be a list of commands of that module in the result. If, however, the - * module has a command with a relevant label, but no enabled one, nothing is returned to indicate that there - * is no legal transition possible. - * - * @param The program in which to search for active commands. - * @param state The current state. - * @param actionIndex The index of the action label to select. - * @return A list of lists of active commands or nothing. - */ - static boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> getActiveCommandsByActionIndex(storm::prism::Program const& program,storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, uint_fast64_t const& actionIndex); - - static std::vector<Choice<ValueType>> getUnlabeledTransitions(storm::prism::Program const& program, bool discreteTimeModel, InternalStateInformation& internalStateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, bool choiceLabeling, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, std::queue<storm::storage::BitVector>& stateQueue, storm::utility::ConstantsComparator<ValueType> const& comparator); - - static std::vector<Choice<ValueType>> getLabeledTransitions(storm::prism::Program const& program, bool discreteTimeModel, InternalStateInformation& internalStateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, bool choiceLabeling, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, std::queue<storm::storage::BitVector>& stateQueue, storm::utility::ConstantsComparator<ValueType> const& comparator); /*! * Builds the transition matrix and the transition reward matrix based for the given program. * @@ -279,7 +242,7 @@ namespace storm { * @return A tuple containing a vector with all rows at which the nondeterministic choices of each state begin * and a vector containing the labels associated with each choice. */ - static boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> buildMatrices(storm::prism::Program const& program, VariableInformation const& variableInformation, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, InternalStateInformation& internalStateInformation, bool commandLabels, bool deterministicModel, bool discreteTimeModel, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression); + boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> buildMatrices(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, InternalStateInformation& internalStateInformation, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression); /*! * Explores the state space of the given program and returns the components of the model as a result. @@ -289,7 +252,7 @@ namespace storm { * @param options A set of options used to customize the building process. * @return A structure containing the components of the resulting model. */ - ModelComponents buildModelComponents(storm::prism::Program const& program, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, Options const& options); + ModelComponents buildModelComponents(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels); /*! * Builds the state labeling for the given program. @@ -299,14 +262,27 @@ namespace storm { * @param internalStateInformation Information about the state space of the program. * @return The state labeling of the given program. */ - static storm::models::sparse::StateLabeling buildStateLabeling(storm::prism::Program const& program, VariableInformation const& variableInformation, InternalStateInformation const& internalStateInformation); + storm::models::sparse::StateLabeling buildStateLabeling(); + + // The program to translate. The necessary transformations are performed upon construction of the builder. + storm::prism::Program program; + + // The options to be used for translating the program. + Options options; + + // The variable information. + storm::generator::VariableInformation variableInformation; + + // Internal information about the states that were explored. + InternalStateInformation internalStateInformation; // This member holds information about reachable states that can be retrieved from the outside after a // successful build. boost::optional<StateInformation> stateInformation; - // This member holds the program that was most recently translated (if any). - boost::optional<storm::prism::Program> preparedProgram; + // A queue of states that still need to be explored. + std::queue<storm::storage::BitVector> statesToExplore; + }; } // namespace adapters diff --git a/src/generator/Choice.cpp b/src/generator/Choice.cpp index 3b6609ebd..8f42b7b3a 100644 --- a/src/generator/Choice.cpp +++ b/src/generator/Choice.cpp @@ -6,7 +6,7 @@ namespace storm { namespace generator { template<typename ValueType, typename StateType> - Choice<ValueType, StateType>::Choice(uint_fast64_t actionIndex, bool markovian) : markovian(markovian), actionIndex(actionIndex), distribution(), totalMass(storm::utility::zero<ValueType>()), choiceReward(storm::utility::zero<ValueType>()) { + Choice<ValueType, StateType>::Choice(uint_fast64_t actionIndex, bool markovian) : markovian(markovian), actionIndex(actionIndex), distribution(), totalMass(storm::utility::zero<ValueType>()), choiceRewards() { // Intentionally left empty. } @@ -89,7 +89,7 @@ namespace storm { template<typename ValueType, typename StateType> void Choice<ValueType, StateType>::addChoiceReward(ValueType const& value) { - choiceReward += value; + choiceRewards.push_back(value); } template<typename ValueType, typename StateType> diff --git a/src/generator/Choice.h b/src/generator/Choice.h index 07eb6efbe..78287d62e 100644 --- a/src/generator/Choice.h +++ b/src/generator/Choice.h @@ -142,8 +142,8 @@ namespace storm { // The total probability mass (or rates) of this choice. ValueType totalMass; - // The reward value associated with this choice. - ValueType choiceReward; + // The reward values associated with this choice. + std::vector<ValueType> choiceRewards; // The labels that are associated with this choice. boost::optional<LabelSet> choiceLabels; diff --git a/src/generator/NextStateGenerator.h b/src/generator/NextStateGenerator.h index 1fdc38cfb..cf89bd1e6 100644 --- a/src/generator/NextStateGenerator.h +++ b/src/generator/NextStateGenerator.h @@ -11,15 +11,15 @@ namespace storm { namespace generator { + typedef storm::storage::BitVector CompressedState; + template<typename ValueType, typename StateType = uint32_t> class NextStateGenerator { public: - typedef storm::storage::BitVector InternalStateType; - typedef StateType (*StateToIdCallback)(InternalStateType const&); - + typedef StateType (*StateToIdCallback)(CompressedState const&); + virtual std::vector<StateType> getInitialStates(StateToIdCallback stateToIdCallback) = 0; - virtual std::vector<Choice<ValueType>> expand(StateType const& state, StateToIdCallback stateToIdCallback) = 0; - virtual ValueType getStateReward(StateType const& state) = 0; + virtual std::vector<Choice<ValueType>> expand(CompressedState const& state, StateToIdCallback stateToIdCallback) = 0; }; } } diff --git a/src/generator/PrismNextStateGenerator.cpp b/src/generator/PrismNextStateGenerator.cpp index 0acf4d8dd..f49aa1b29 100644 --- a/src/generator/PrismNextStateGenerator.cpp +++ b/src/generator/PrismNextStateGenerator.cpp @@ -1,22 +1,263 @@ #include "src/generator/PrismNextStateGenerator.h" +#include "src/utility/constants.h" +#include "src/utility/macros.h" +#include "src/exceptions/WrongFormatException.h" + namespace storm { namespace generator { template<typename ValueType, typename StateType> - PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program) : program(program) { + PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation, bool buildChoiceLabeling) : program(program), selectedRewardModels(), buildChoiceLabeling(buildChoiceLabeling), variableInformation(variableInformation), evaluator(), comparator() { // Intentionally left empty. } template<typename ValueType, typename StateType> - std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::expand(StateType const& state, typename NextStateGenerator<ValueType, StateType>::StateToIdCallback stateToIdCallback) { - // TODO + void PrismNextStateGenerator<ValueType, StateType>::addRewardModel(storm::prism::RewardModel const& rewardModel) { + selectedRewardModels.push_back(rewardModel); } template<typename ValueType, typename StateType> - ValueType PrismNextStateGenerator<ValueType, StateType>::getStateReward(StateType const& state) { + std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::expand(CompressedState const& state, typename NextStateGenerator<ValueType, StateType>::StateToIdCallback stateToIdCallback) { // TODO } + template<typename ValueType, typename StateType> + void PrismNextStateGenerator<ValueType, StateType>::unpackStateIntoEvaluator(storm::storage::BitVector const& state) { + for (auto const& booleanVariable : variableInformation.booleanVariables) { + evaluator.setBooleanValue(booleanVariable.variable, state.get(booleanVariable.bitOffset)); + } + for (auto const& integerVariable : variableInformation.integerVariables) { + evaluator.setIntegerValue(integerVariable.variable, state.getAsInt(integerVariable.bitOffset, integerVariable.bitWidth) + integerVariable.lowerBound); + } + } + + template<typename ValueType, typename StateType> + CompressedState PrismNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::prism::Update const& update) { + return applyUpdate(variableInformation, state, state, update); + } + + template<typename ValueType, typename StateType> + CompressedState PrismNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, CompressedState const& baseState, storm::prism::Update const& update) { + CompressedState newState(state); + + auto assignmentIt = update.getAssignments().begin(); + auto assignmentIte = update.getAssignments().end(); + + // Iterate over all boolean assignments and carry them out. + auto boolIt = variableInformation.booleanVariables.begin(); + for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasBooleanType(); ++assignmentIt) { + while (assignmentIt->getVariable() != boolIt->variable) { + ++boolIt; + } + newState.set(boolIt->bitOffset, evaluator.asBool(assignmentIt->getExpression())); + } + + // Iterate over all integer assignments and carry them out. + auto integerIt = variableInformation.integerVariables.begin(); + for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasIntegerType(); ++assignmentIt) { + while (assignmentIt->getVariable() != integerIt->variable) { + ++integerIt; + } + int_fast64_t assignedValue = evaluator.asInt(assignmentIt->getExpression()); + STORM_LOG_THROW(assignedValue <= integerIt->upperBound, storm::exceptions::WrongFormatException, "The update " << update << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getVariableName() << "'."); + newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, assignedValue - integerIt->lowerBound); + STORM_LOG_ASSERT(static_cast<int_fast64_t>(newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote " << assignedValue << ")."); + } + + // Check that we processed all assignments. + STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed."); + + return newState; + } + + template<typename ValueType, typename StateType> + boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> PrismNextStateGenerator<ValueType, StateType>::getActiveCommandsByActionIndex(uint_fast64_t const& actionIndex) { + boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> result((std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>())); + + // Iterate over all modules. + for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) { + storm::prism::Module const& module = program.getModule(i); + + // If the module has no command labeled with the given action, we can skip this module. + if (!module.hasActionIndex(actionIndex)) { + continue; + } + + std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex); + + // If the module contains the action, but there is no command in the module that is labeled with + // this action, we don't have any feasible command combinations. + if (commandIndices.empty()) { + return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>(); + } + + std::vector<std::reference_wrapper<storm::prism::Command const>> commands; + + // Look up commands by their indices and add them if the guard evaluates to true in the given state. + for (uint_fast64_t commandIndex : commandIndices) { + storm::prism::Command const& command = module.getCommand(commandIndex); + if (evaluator.asBool(command.getGuardExpression())) { + commands.push_back(command); + } + } + + // If there was no enabled command although the module has some command with the required action label, + // we must not return anything. + if (commands.size() == 0) { + return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>(); + } + + result.get().push_back(std::move(commands)); + } + + return result; + } + + template<typename ValueType, typename StateType> + std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getUnlabeledTransitions(CompressedState const& state, StateToIdCallback stateToIdCallback) { + std::vector<Choice<ValueType>> result; + + // Iterate over all modules. + for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) { + storm::prism::Module const& module = program.getModule(i); + + // Iterate over all commands. + for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) { + storm::prism::Command const& command = module.getCommand(j); + + // Only consider unlabeled commands. + if (command.isLabeled()) continue; + + // Skip the command, if it is not enabled. + if (!evaluator.asBool(command.getGuardExpression())) { + continue; + } + + result.push_back(Choice<ValueType>(0, buildChoiceLabeling)); + Choice<ValueType>& choice = result.back(); + + // Remember the command labels only if we were asked to. + if (buildChoiceLabeling) { + choice.addChoiceLabel(command.getGlobalIndex()); + } + + // Iterate over all updates of the current command. + ValueType probabilitySum = storm::utility::zero<ValueType>(); + for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) { + storm::prism::Update const& update = command.getUpdate(k); + + // Obtain target state index and add it to the list of known states. If it has not yet been + // seen, we also add it to the set of states that have yet to be explored. + StateType stateIndex = stateToIdCallback(applyUpdate(state, update)); + + // Update the choice by adding the probability/target state to it. + ValueType probability = evaluator.asRational(update.getLikelihoodExpression()); + choice.addProbability(stateIndex, probability); + probabilitySum += probability; + } + + // Check that the resulting distribution is in fact a distribution. + STORM_LOG_THROW(!program.isDiscreteTimeModel() || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for command '" << command << "' (actually sum to " << probabilitySum << ")."); + } + } + + return result; + } + + template<typename ValueType, typename StateType> + std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getLabeledTransitions(CompressedState const& state, StateToIdCallback stateToIdCallback) { + std::vector<Choice<ValueType>> result; + + for (uint_fast64_t actionIndex : program.getSynchronizingActionIndices()) { + boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> optionalActiveCommandLists = getActiveCommandsByActionIndex(program, evaluator, actionIndex); + + // Only process this action label, if there is at least one feasible solution. + if (optionalActiveCommandLists) { + std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> const& activeCommandList = optionalActiveCommandLists.get(); + std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> iteratorList(activeCommandList.size()); + + // Initialize the list of iterators. + for (size_t i = 0; i < activeCommandList.size(); ++i) { + iteratorList[i] = activeCommandList[i].cbegin(); + } + + // As long as there is one feasible combination of commands, keep on expanding it. + bool done = false; + while (!done) { + std::unordered_map<CompressedState, ValueType>* currentTargetStates = new std::unordered_map<CompressedState, ValueType>(); + std::unordered_map<CompressedState, ValueType>* newTargetStates = new std::unordered_map<CompressedState, ValueType>(); + currentTargetStates->emplace(state, storm::utility::one<ValueType>()); + + for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { + storm::prism::Command const& command = *iteratorList[i]; + + for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) { + storm::prism::Update const& update = command.getUpdate(j); + + for (auto const& stateProbabilityPair : *currentTargetStates) { + // Compute the new state under the current update and add it to the set of new target states. + CompressedState newTargetState = applyUpdate(stateProbabilityPair.first, state, update); + newTargetStates->emplace(newTargetState, stateProbabilityPair.second * evaluator.asRational(update.getLikelihoodExpression())); + } + } + + // If there is one more command to come, shift the target states one time step back. + if (i < iteratorList.size() - 1) { + delete currentTargetStates; + currentTargetStates = newTargetStates; + newTargetStates = new std::unordered_map<CompressedState, ValueType>(); + } + } + + // At this point, we applied all commands of the current command combination and newTargetStates + // contains all target states and their respective probabilities. That means we are now ready to + // add the choice to the list of transitions. + result.push_back(Choice<ValueType>(actionIndex, buildChoiceLabeling)); + + // Now create the actual distribution. + Choice<ValueType>& choice = result.back(); + + // Remember the command labels only if we were asked to. + if (buildChoiceLabeling) { + // Add the labels of all commands to this choice. + for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { + choice.addChoiceLabel(iteratorList[i]->get().getGlobalIndex()); + } + } + + ValueType probabilitySum = storm::utility::zero<ValueType>(); + for (auto const& stateProbabilityPair : *newTargetStates) { + StateType actualIndex = stateToIdCallback(stateProbabilityPair.first); + choice.addProbability(actualIndex, stateProbabilityPair.second); + probabilitySum += stateProbabilityPair.second; + } + + // Check that the resulting distribution is in fact a distribution. + STORM_LOG_THROW(!program.isDiscreteTimeModel() || !comparator.isConstant(probabilitySum) || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not some to one for some command (actually sum to " << probabilitySum << ")."); + + // Dispose of the temporary maps. + delete currentTargetStates; + delete newTargetStates; + + // Now, check whether there is one more command combination to consider. + bool movedIterator = false; + for (int_fast64_t j = iteratorList.size() - 1; j >= 0; --j) { + ++iteratorList[j]; + if (iteratorList[j] != activeCommandList[j].end()) { + movedIterator = true; + } else { + // Reset the iterator to the beginning of the list. + iteratorList[j] = activeCommandList[j].begin(); + } + } + + done = !movedIterator; + } + } + } + + return result; + } } } \ No newline at end of file diff --git a/src/generator/PrismNextStateGenerator.h b/src/generator/PrismNextStateGenerator.h index 1330d4420..f5fabe5f7 100644 --- a/src/generator/PrismNextStateGenerator.h +++ b/src/generator/PrismNextStateGenerator.h @@ -2,8 +2,10 @@ #define STORM_GENERATOR_PRISMNEXTSTATEGENERATOR_H_ #include "src/generator/NextStateGenerator.h" +#include "src/generator/VariableInformation.h" #include "src/storage/prism/Program.h" +#include "src/storage/expressions/ExpressionEvaluator.h" namespace storm { namespace generator { @@ -13,17 +15,97 @@ namespace storm { public: typedef typename NextStateGenerator<ValueType, StateType>::StateToIdCallback StateToIdCallback; - PrismNextStateGenerator(storm::prism::Program const& program); + PrismNextStateGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation, bool buildChoiceLabeling); - virtual std::vector<StateType> getInitialStates(StateToIdCallback stateToIdCallback) = 0; - virtual std::vector<Choice<ValueType>> expand(StateType const& state, StateToIdCallback stateToIdCallback) override; - virtual ValueType getStateReward(StateType const& state) override; + /*! + * Adds a reward model to the list of selected reward models () + */ + void addRewardModel(storm::prism::RewardModel const& rewardModel); + virtual std::vector<StateType> getInitialStates(StateToIdCallback stateToIdCallback) = 0; + virtual std::vector<Choice<ValueType>> expand(CompressedState const& state, StateToIdCallback stateToIdCallback) override; + private: + /*! + * Unpacks the compressed state into the evaluator. + * + * @param state The state to unpack. + */ + void unpackStateIntoEvaluator(CompressedState const& state); + + /*! + * Applies an update to the given state and returns the resulting new state object. This methods does not + * modify the given state but returns a new one. + * + * @params state The state to which to apply the update. + * @params update The update to apply. + * @return The resulting state. + */ + CompressedState applyUpdate(CompressedState const& state, storm::prism::Update const& update); + + /*! + * Applies an update to the given state and returns the resulting new state object. The update is evaluated + * over the variable values of the given base state. This methods does not modify the given state but + * returns a new one. + * + * @param state The state to which to apply the update. + * @param baseState The state used for evaluating the update. + * @param update The update to apply. + * @return The resulting state. + */ + CompressedState applyUpdate(CompressedState const& state, CompressedState const& baseState, storm::prism::Update const& update); + + /*! + * Retrieves all commands that are labeled with the given label and enabled in the given state, grouped by + * modules. + * + * This function will iterate over all modules and retrieve all commands that are labeled with the given + * action and active (i.e. enabled) in the current state. The result is a list of lists of commands in which + * the inner lists contain all commands of exactly one module. If a module does not have *any* (including + * disabled) commands, there will not be a list of commands of that module in the result. If, however, the + * module has a command with a relevant label, but no enabled one, nothing is returned to indicate that there + * is no legal transition possible. + * + * @param The program in which to search for active commands. + * @param state The current state. + * @param actionIndex The index of the action label to select. + * @return A list of lists of active commands or nothing. + */ + boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> getActiveCommandsByActionIndex(uint_fast64_t const& actionIndex); + + /*! + * Retrieves all unlabeled choices possible from the given state. + * + * @param state The state for which to retrieve the unlabeled choices. + * @return The unlabeled choices of the state. + */ + std::vector<Choice<ValueType>> getUnlabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback); + + /*! + * Retrieves all labeled choices possible from the given state. + * + * @param state The state for which to retrieve the unlabeled choices. + * @return The labeled choices of the state. + */ + std::vector<Choice<ValueType>> getLabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback); + // The program used for the generation of next states. - storm::prism::Program program; + storm::prism::Program const& program; + + // The reward models that need to be considered. + std::vector<std::reference_wrapper<storm::prism::RewardModel const>> selectedRewardModels; + + // A flag that stores whether or not to build the choice labeling. + bool buildChoiceLabeling; + + // Information about how the variables are packed + VariableInformation const& variableInformation; + // An evaluator used to evaluate expressions. + storm::expressions::ExpressionEvaluator<ValueType> evaluator; + // A comparator used to compare constants. + storm::utility::ConstantsComparator<ValueType> comparator; }; } diff --git a/src/generator/VariableInformation.cpp b/src/generator/VariableInformation.cpp new file mode 100644 index 000000000..7f7ed357e --- /dev/null +++ b/src/generator/VariableInformation.cpp @@ -0,0 +1,42 @@ +#include "src/generator/prism/VariableInformation.h" + +#include "src/utility/macros.h" +#include "src/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace generator { + + BooleanVariableInformation::BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset) : variable(variable), initialValue(initialValue), bitOffset(bitOffset) { + // Intentionally left empty. + } + + IntegerVariableInformation::IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth) : variable(variable), initialValue(initialValue), lowerBound(lowerBound), upperBound(upperBound), bitOffset(bitOffset), bitWidth(bitWidth) { + // Intentionally left empty. + } + + VariableInformation::VariableInformation(storm::expressions::ExpressionManager const& manager) : manager(manager) { + // Intentionally left empty. + } + + uint_fast64_t VariableInformation::getBitOffset(storm::expressions::Variable const& variable) const { + auto const& booleanIndex = booleanVariableToIndexMap.find(variable); + if (booleanIndex != booleanVariableToIndexMap.end()) { + return booleanVariables[booleanIndex->second].bitOffset; + } + auto const& integerIndex = integerVariableToIndexMap.find(variable); + if (integerIndex != integerVariableToIndexMap.end()) { + return integerVariables[integerIndex->second].bitOffset; + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit index of unknown variable."); + } + + uint_fast64_t VariableInformation::getBitWidth(storm::expressions::Variable const& variable) const { + auto const& integerIndex = integerVariableToIndexMap.find(variable); + if (integerIndex != integerVariableToIndexMap.end()) { + return integerVariables[integerIndex->second].bitWidth; + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit width of unknown variable."); + } + + } +} \ No newline at end of file diff --git a/src/generator/VariableInformation.h b/src/generator/VariableInformation.h new file mode 100644 index 000000000..c1f06e741 --- /dev/null +++ b/src/generator/VariableInformation.h @@ -0,0 +1,71 @@ +#ifndef STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ +#define STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ + +#include <vector> +#include <boost/container/flat_map.hpp> + +#include "src/storage/expressions/Variable.h" + +namespace storm { + namespace generator { + + // A structure storing information about the boolean variables of the program. + struct BooleanVariableInformation { + BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset); + + // The boolean variable. + storm::expressions::Variable variable; + + // Its initial value. + bool initialValue; + + // Its bit offset in the compressed state. + uint_fast64_t bitOffset; + }; + + // A structure storing information about the integer variables of the program. + struct IntegerVariableInformation { + IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth); + + // The integer variable. + storm::expressions::Variable variable; + + // Its initial value. + int_fast64_t initialValue; + + // The lower bound of its range. + int_fast64_t lowerBound; + + // The upper bound of its range. + int_fast64_t upperBound; + + // Its bit offset in the compressed state. + uint_fast64_t bitOffset; + + // Its bit width in the compressed state. + uint_fast64_t bitWidth; + }; + + // A structure storing information about the used variables of the program. + struct VariableInformation { + VariableInformation(storm::expressions::ExpressionManager const& manager); + + // Provide methods to access the bit offset and width of variables in the compressed state. + uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const; + uint_fast64_t getBitWidth(storm::expressions::Variable const& variable) const; + + // The known boolean variables. + boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> booleanVariableToIndexMap; + std::vector<BooleanVariableInformation> booleanVariables; + + // The known integer variables. + boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> integerVariableToIndexMap; + std::vector<IntegerVariableInformation> integerVariables; + + storm::expressions::ExpressionManager const& manager; + }; + + } +} + +#endif /* STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ */ \ No newline at end of file diff --git a/src/generator/prism/VariableInformation.cpp b/src/generator/prism/VariableInformation.cpp deleted file mode 100644 index f648eda1b..000000000 --- a/src/generator/prism/VariableInformation.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "src/generator/prism/VariableInformation.h" - -#include "src/utility/macros.h" -#include "src/exceptions/InvalidArgumentException.h" - -namespace storm { - namespace generator { - namespace prism { - - BooleanVariableInformation::BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset) : variable(variable), initialValue(initialValue), bitOffset(bitOffset) { - // Intentionally left empty. - } - - IntegerVariableInformation::IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth) : variable(variable), initialValue(initialValue), lowerBound(lowerBound), upperBound(upperBound), bitOffset(bitOffset), bitWidth(bitWidth) { - // Intentionally left empty. - } - - VariableInformation::VariableInformation(storm::expressions::ExpressionManager const& manager) : manager(manager) { - // Intentionally left empty. - } - - uint_fast64_t VariableInformation::getBitOffset(storm::expressions::Variable const& variable) const { - auto const& booleanIndex = booleanVariableToIndexMap.find(variable); - if (booleanIndex != booleanVariableToIndexMap.end()) { - return booleanVariables[booleanIndex->second].bitOffset; - } - auto const& integerIndex = integerVariableToIndexMap.find(variable); - if (integerIndex != integerVariableToIndexMap.end()) { - return integerVariables[integerIndex->second].bitOffset; - } - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit index of unknown variable."); - } - - uint_fast64_t VariableInformation::getBitWidth(storm::expressions::Variable const& variable) const { - auto const& integerIndex = integerVariableToIndexMap.find(variable); - if (integerIndex != integerVariableToIndexMap.end()) { - return integerVariables[integerIndex->second].bitWidth; - } - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit width of unknown variable."); - } - - } - } -} \ No newline at end of file diff --git a/src/generator/prism/VariableInformation.h b/src/generator/prism/VariableInformation.h deleted file mode 100644 index 56ac7bda2..000000000 --- a/src/generator/prism/VariableInformation.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ -#define STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ - -#include <vector> -#include <boost/container/flat_map.hpp> - -#include "src/storage/expressions/Variable.h" - -namespace storm { - namespace generator { - namespace prism { - - // A structure storing information about the boolean variables of the program. - struct BooleanVariableInformation { - BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset); - - // The boolean variable. - storm::expressions::Variable variable; - - // Its initial value. - bool initialValue; - - // Its bit offset in the compressed state. - uint_fast64_t bitOffset; - }; - - // A structure storing information about the integer variables of the program. - struct IntegerVariableInformation { - IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth); - - // The integer variable. - storm::expressions::Variable variable; - - // Its initial value. - int_fast64_t initialValue; - - // The lower bound of its range. - int_fast64_t lowerBound; - - // The upper bound of its range. - int_fast64_t upperBound; - - // Its bit offset in the compressed state. - uint_fast64_t bitOffset; - - // Its bit width in the compressed state. - uint_fast64_t bitWidth; - }; - - // A structure storing information about the used variables of the program. - struct VariableInformation { - VariableInformation(storm::expressions::ExpressionManager const& manager); - - // Provide methods to access the bit offset and width of variables in the compressed state. - uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const; - uint_fast64_t getBitWidth(storm::expressions::Variable const& variable) const; - - // The known boolean variables. - boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> booleanVariableToIndexMap; - std::vector<BooleanVariableInformation> booleanVariables; - - // The known integer variables. - boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> integerVariableToIndexMap; - std::vector<IntegerVariableInformation> integerVariables; - - storm::expressions::ExpressionManager const& manager; - }; - - } - } -} - -#endif /* STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ */ \ No newline at end of file diff --git a/src/storage/prism/Program.cpp b/src/storage/prism/Program.cpp index bf8caf4a8..0f5aea4a8 100644 --- a/src/storage/prism/Program.cpp +++ b/src/storage/prism/Program.cpp @@ -77,6 +77,10 @@ namespace storm { return modelType; } + bool Program::isDiscreteTimeModel() const { + return modelType == ModelType::DTMC || modelType == ModelType::MDP; + } + bool Program::hasUndefinedConstants() const { for (auto const& constant : this->getConstants()) { if (!constant.isDefined()) { diff --git a/src/storage/prism/Program.h b/src/storage/prism/Program.h index 45ac16b62..1d091c294 100644 --- a/src/storage/prism/Program.h +++ b/src/storage/prism/Program.h @@ -66,6 +66,18 @@ namespace storm { * @return The type of the model. */ ModelType getModelType() const; + + /*! + * Retrieves whether the model is a discrete-time model, i.e. a DTMC or an MDP. + * + * @return True iff the model is a discrete-time model. + */ + bool isDiscreteTimeModel() const; + + /*! + * Retrieves whether the model is one without nondeterministic choices, i.e. a DTMC or a CTMC. + */ + bool isDeterministicModel() const; /*! * Retrieves whether there are undefined constants of any type in the program. From 865345c7bf69a3dd6c208aa016d55d0d03145ff8 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Wed, 24 Feb 2016 10:27:52 +0100 Subject: [PATCH 03/33] a little morning code Former-commit-id: 9cb63427c66ed48e3454d1e221a4a02cf60e5514 --- src/generator/NextStateGenerator.h | 4 +-- src/generator/PrismNextStateGenerator.cpp | 7 +---- src/generator/PrismNextStateGenerator.h | 21 +++----------- src/generator/StateBehavior.cpp | 17 +++++++++++ src/generator/StateBehavior.h | 35 +++++++++++++++++++++++ 5 files changed, 59 insertions(+), 25 deletions(-) create mode 100644 src/generator/StateBehavior.cpp create mode 100644 src/generator/StateBehavior.h diff --git a/src/generator/NextStateGenerator.h b/src/generator/NextStateGenerator.h index cf89bd1e6..8e8e4bbdb 100644 --- a/src/generator/NextStateGenerator.h +++ b/src/generator/NextStateGenerator.h @@ -7,7 +7,7 @@ #include "src/storage/sparse/StateType.h" #include "src/storage/BitVector.h" -#include "src/generator/Choice.h" +#include "src/generator/StateBehavior.h" namespace storm { namespace generator { @@ -19,7 +19,7 @@ namespace storm { typedef StateType (*StateToIdCallback)(CompressedState const&); virtual std::vector<StateType> getInitialStates(StateToIdCallback stateToIdCallback) = 0; - virtual std::vector<Choice<ValueType>> expand(CompressedState const& state, StateToIdCallback stateToIdCallback) = 0; + virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback stateToIdCallback) = 0; }; } } diff --git a/src/generator/PrismNextStateGenerator.cpp b/src/generator/PrismNextStateGenerator.cpp index f49aa1b29..a23ed29a6 100644 --- a/src/generator/PrismNextStateGenerator.cpp +++ b/src/generator/PrismNextStateGenerator.cpp @@ -18,7 +18,7 @@ namespace storm { } template<typename ValueType, typename StateType> - std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::expand(CompressedState const& state, typename NextStateGenerator<ValueType, StateType>::StateToIdCallback stateToIdCallback) { + StateBehavior<ValueType, StateType> PrismNextStateGenerator<ValueType, StateType>::expand(CompressedState const& state, typename NextStateGenerator<ValueType, StateType>::StateToIdCallback stateToIdCallback) { // TODO } @@ -34,11 +34,6 @@ namespace storm { template<typename ValueType, typename StateType> CompressedState PrismNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::prism::Update const& update) { - return applyUpdate(variableInformation, state, state, update); - } - - template<typename ValueType, typename StateType> - CompressedState PrismNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, CompressedState const& baseState, storm::prism::Update const& update) { CompressedState newState(state); auto assignmentIt = update.getAssignments().begin(); diff --git a/src/generator/PrismNextStateGenerator.h b/src/generator/PrismNextStateGenerator.h index f5fabe5f7..d3660ce05 100644 --- a/src/generator/PrismNextStateGenerator.h +++ b/src/generator/PrismNextStateGenerator.h @@ -23,7 +23,7 @@ namespace storm { void addRewardModel(storm::prism::RewardModel const& rewardModel); virtual std::vector<StateType> getInitialStates(StateToIdCallback stateToIdCallback) = 0; - virtual std::vector<Choice<ValueType>> expand(CompressedState const& state, StateToIdCallback stateToIdCallback) override; + virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback stateToIdCallback) override; private: /*! @@ -34,27 +34,14 @@ namespace storm { void unpackStateIntoEvaluator(CompressedState const& state); /*! - * Applies an update to the given state and returns the resulting new state object. This methods does not - * modify the given state but returns a new one. - * - * @params state The state to which to apply the update. + * Applies an update to the state currently loaded into the evaluator and applies the resulting values to + * the given compressed state. + * @params state The state to which to apply the new values. * @params update The update to apply. * @return The resulting state. */ CompressedState applyUpdate(CompressedState const& state, storm::prism::Update const& update); - /*! - * Applies an update to the given state and returns the resulting new state object. The update is evaluated - * over the variable values of the given base state. This methods does not modify the given state but - * returns a new one. - * - * @param state The state to which to apply the update. - * @param baseState The state used for evaluating the update. - * @param update The update to apply. - * @return The resulting state. - */ - CompressedState applyUpdate(CompressedState const& state, CompressedState const& baseState, storm::prism::Update const& update); - /*! * Retrieves all commands that are labeled with the given label and enabled in the given state, grouped by * modules. diff --git a/src/generator/StateBehavior.cpp b/src/generator/StateBehavior.cpp new file mode 100644 index 000000000..5868a1e40 --- /dev/null +++ b/src/generator/StateBehavior.cpp @@ -0,0 +1,17 @@ +#include "src/generator/StateBehavior.h" + +namespace storm { + namespace generator { + + template<typename ValueType, typename StateType> + void StateBehavior<ValueType, StateType>::addChoice(Choice<ValueType, StateType>&& choice) { + choices.push_back(std::move(choice)); + } + + template<typename ValueType, typename StateType> + void StateBehavior<ValueType, StateType>::addStateReward(ValueType const& stateReward) { + stateRewards.push_back(stateReward); + } + + } +} \ No newline at end of file diff --git a/src/generator/StateBehavior.h b/src/generator/StateBehavior.h new file mode 100644 index 000000000..b4feecb34 --- /dev/null +++ b/src/generator/StateBehavior.h @@ -0,0 +1,35 @@ +#ifndef STORM_GENERATOR_PRISM_STATEBEHAVIOR_H_ +#define STORM_GENERATOR_PRISM_STATEBEHAVIOR_H_ + +#include <cstdint> + +#include "src/generator/Choice.h" + +namespace storm { + namespace generator { + + template<typename ValueType, typename StateType = uint32_t> + class StateBehavior { + public: + /*! + * Adds the given choice to the behavior of the state. + */ + void addChoice(Choice<ValueType, StateType>&& choice); + + /*! + * Adds the given state reward to the behavior of the state. + */ + void addStateReward(ValueType const& stateReward); + + private: + // The choices available in the state. + std::vector<Choice<ValueType, StateType>> choices; + + // The state rewards (under the different, selected reward models) of the state. + std::vector<ValueType> stateRewards; + }; + + } +} + +#endif /* STORM_GENERATOR_PRISM_STATEBEHAVIOR_H_ */ From a75e0f5323f138c70384a54c1cc449c69e37c1c2 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Wed, 24 Feb 2016 18:58:25 +0100 Subject: [PATCH 04/33] more work wrt cleaner model exploration Former-commit-id: f24d618bdf08e22aa28f7f6baf045b56bc98e9d8 --- src/builder/ExplicitPrismModelBuilder.cpp | 184 ++++++++--------- src/builder/ExplicitPrismModelBuilder.h | 7 +- src/generator/NextStateGenerator.h | 8 +- src/generator/PrismNextStateGenerator.cpp | 136 ++++++++++++- src/generator/PrismNextStateGenerator.h | 7 +- src/generator/VariableInformation.cpp | 37 +++- src/generator/VariableInformation.h | 9 +- src/storage/BitVector.cpp | 229 ++++++++++------------ src/storage/BitVector.h | 7 +- 9 files changed, 386 insertions(+), 238 deletions(-) diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp index 039048111..4a777c6f9 100644 --- a/src/builder/ExplicitPrismModelBuilder.cpp +++ b/src/builder/ExplicitPrismModelBuilder.cpp @@ -11,6 +11,8 @@ #include "src/settings/modules/GeneralSettings.h" +#include "src/generator/PrismNextStateGenerator.h" + #include "src/utility/prism.h" #include "src/utility/macros.h" #include "src/utility/ConstantsComparator.h" @@ -37,7 +39,7 @@ namespace storm { stateRewardVector.resize(rowGroupCount); optionalStateRewardVector = std::move(stateRewardVector); } - + boost::optional<std::vector<ValueType>> optionalStateActionRewardVector; if (hasStateActionRewards) { stateActionRewardVector.resize(rowCount); @@ -75,12 +77,12 @@ namespace storm { ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::InternalStateInformation::InternalStateInformation(uint64_t bitsPerState) : stateStorage(bitsPerState, 10000000), bitsPerState(bitsPerState), numberOfStates() { // Intentionally left empty. } - + template <typename ValueType, typename RewardModelType, typename StateType> ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), rewardModels(), choiceLabeling() { // Intentionally left empty. } - + template <typename ValueType, typename RewardModelType, typename StateType> ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options() : buildCommandLabels(false), buildAllRewardModels(true), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(true), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() { // Intentionally left empty. @@ -135,7 +137,7 @@ namespace storm { } } } - + template <typename ValueType, typename RewardModelType, typename StateType> void ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::preserveFormula(storm::logic::Formula const& formula) { // If we already had terminal states, we need to erase them. @@ -180,7 +182,7 @@ namespace storm { } template <typename ValueType, typename RewardModelType, typename StateType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ExplicitPrismModelBuilder(storm::prism::Program const& program, Options const& options) : options(options), program(program) { + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ExplicitPrismModelBuilder(storm::prism::Program const& program, Options const& options) : options(options), program(program), variableInformation(program), internalStateInformation(variableInformation.getTotalBitOffset()) { // Start by defining the undefined constants in the model. if (options.constantDefinitions) { this->program = program.defineUndefinedConstants(options.constantDefinitions.get()); @@ -189,56 +191,48 @@ namespace storm { } // If the program still contains undefined constants and we are not in a parametric setting, assemble an appropriate error message. -#ifdef STORM_HAVE_CARL - // If the program either has undefined constants or we are building a parametric model, but the parameters - // not only appear in the probabilities, we re if (!std::is_same<ValueType, storm::RationalFunction>::value && this->program.hasUndefinedConstants()) { -#else - if (this->program->hasUndefinedConstants()) { -#endif - std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = this->program.getUndefinedConstants(); - std::stringstream stream; - bool printComma = false; - for (auto const& constant : undefinedConstants) { - if (printComma) { - stream << ", "; - } else { - printComma = true; - } - stream << constant.get().getName() << " (" << constant.get().getType() << ")"; + std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = this->program.getUndefinedConstants(); + std::stringstream stream; + bool printComma = false; + for (auto const& constant : undefinedConstants) { + if (printComma) { + stream << ", "; + } else { + printComma = true; } - stream << "."; - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str()); -#ifdef STORM_HAVE_CARL - } else if (std::is_same<ValueType, storm::RationalFunction>::value && !this->program.hasUndefinedConstantsOnlyInUpdateProbabilitiesAndRewards()) { - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The program contains undefined constants that appear in some places other than update probabilities and reward value expressions, which is not admitted."); -#endif + stream << constant.get().getName() << " (" << constant.get().getType() << ")"; } - - // If the set of labels we are supposed to built is restricted, we need to remove the other labels from the program. - if (options.labelsToBuild) { - if (!options.buildAllLabels) { - this->program.filterLabels(options.labelsToBuild.get()); - } + stream << "."; + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str()); + } else if (std::is_same<ValueType, storm::RationalFunction>::value && !this->program.hasUndefinedConstantsOnlyInUpdateProbabilitiesAndRewards()) { + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The program contains undefined constants that appear in some places other than update probabilities and reward value expressions, which is not admitted."); + } + + // If the set of labels we are supposed to built is restricted, we need to remove the other labels from the program. + if (options.labelsToBuild) { + if (!options.buildAllLabels) { + this->program.filterLabels(options.labelsToBuild.get()); } + } + + // If we need to build labels for expressions that may appear in some formula, we need to add appropriate + // labels to the program. + if (options.expressionLabels) { + std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = this->program.getConstantsSubstitution(); - // If we need to build labels for expressions that may appear in some formula, we need to add appropriate - // labels to the program. - if (options.expressionLabels) { - std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = this->program.getConstantsSubstitution(); - - for (auto const& expression : options.expressionLabels.get()) { - std::stringstream stream; - stream << expression.substitute(constantsSubstitution); - std::string name = stream.str(); - if (!this->program.hasLabel(name)) { - this->program.addLabel(name, expression); - } + for (auto const& expression : options.expressionLabels.get()) { + std::stringstream stream; + stream << expression.substitute(constantsSubstitution); + std::string name = stream.str(); + if (!this->program.hasLabel(name)) { + this->program.addLabel(name, expression); } } - - // Now that the program is fixed, we we need to substitute all constants with their concrete value. - this->program = program.substituteConstants(); + } + + // Now that the program is fixed, we we need to substitute all constants with their concrete value. + this->program = program.substituteConstants(); } template <typename ValueType, typename RewardModelType, typename StateType> @@ -255,15 +249,15 @@ namespace storm { template <typename ValueType, typename RewardModelType, typename StateType> std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::translate() { STORM_LOG_DEBUG("Building representation of program:" << std::endl << *program << std::endl); - + // Select the appropriate reward models (after the constants have been substituted). std::vector<std::reference_wrapper<storm::prism::RewardModel const>> selectedRewardModels; - + // First, we make sure that all selected reward models actually exist. for (auto const& rewardModelName : options.rewardModelsToBuild) { STORM_LOG_THROW(rewardModelName.empty() || program.hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'."); } - + for (auto const& rewardModel : program.getRewardModels()) { if (options.buildAllRewardModels || options.rewardModelsToBuild.find(rewardModel.getName()) != options.rewardModelsToBuild.end()) { selectedRewardModels.push_back(rewardModel); @@ -274,7 +268,7 @@ namespace storm { if (selectedRewardModels.empty() && program.getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") { selectedRewardModels.push_back(program.getRewardModel(0)); } - + ModelComponents modelComponents = buildModelComponents(*program, selectedRewardModels, options); std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> result; @@ -295,10 +289,10 @@ namespace storm { return result; } - + template <typename ValueType, typename RewardModelType, typename StateType> storm::expressions::SimpleValuation ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::unpackStateIntoValuation(storm::storage::BitVector const& currentState) { - storm::expressions::SimpleValuation result(variableInformation.manager.getSharedPointer()); + storm::expressions::SimpleValuation result(program.getManager().getSharedPointer()); for (auto const& booleanVariable : variableInformation.booleanVariables) { result.setBooleanValue(booleanVariable.variable, currentState.get(booleanVariable.bitOffset)); } @@ -322,17 +316,54 @@ namespace storm { return actualIndexBucketPair.first; } - + template <typename ValueType, typename RewardModelType, typename StateType> - boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildMatrices(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, InternalStateInformation& internalStateInformation, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression) { + boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildMatrices(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression) { // Create choice labels, if requested, boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> choiceLabels; if (options.buildCommandLabels) { choiceLabels = std::vector<boost::container::flat_set<uint_fast64_t>>(); } + + // Create a generator that is able to expand states. + storm::generator::PrismNextStateGenerator<ValueType, StateType> generator(program, variableInformation, options.buildCommandLabels); + for (auto const& rewardModel : selectedRewardModels) { + generator.addRewardModel(rewardModel.get()); + } + + // Create a callback for the next-state generator to enable it to request the index of states. + std::function<StateType (CompressedState const&)> stateToIdCallback = std::bind1st(&ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex, this); - // A comparator that can be used to check whether we actually have distributions. - storm::utility::ConstantsComparator<ValueType> comparator; + // Let the generator create all initial states. + generator.getInitialStates(stateToIdCallback); + + // Now explore the current state until there is no more reachable state. + uint_fast64_t currentRow = 0; + + // Perform a DFS through the model. + while (!statesToExplore.empty()) { + // Get the first state in the queue. + std::pair<CompressedState, StateType> currentState = internalStateInformation.stateStorage.getBucketAndValue(statesToExplore.front()); + statesToExplore.pop(); + + STORM_LOG_TRACE("Exploring state with id " << currentState.second << "."); + + bool deadlockOnPurpose = false; + if (terminalExpression && evaluator.asBool(terminalExpression.get())) { + // Nothing to do in this case. + deadlockOnPurpose = true; + } else { + // Retrieve all choices for the current state. + allUnlabeledChoices = getUnlabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator); + allLabeledChoices = getLabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator); + } + + + } + + + + // Initialize a queue and insert the initial state. std::queue<storm::storage::BitVector> stateQueue; @@ -420,7 +451,7 @@ namespace storm { std::cout << unpackStateIntoValuation(currentState, variableInformation).toString(true) << std::endl; STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Error while creating sparse matrix from probabilistic program: found deadlock state. For fixing these, please provide the appropriate option."); - + } } else if (totalNumberOfChoices == 1) { if (!deterministicModel) { @@ -468,7 +499,7 @@ namespace storm { // or compose them to one choice. if (deterministicModel) { Choice<ValueType> globalChoice; - + // We need to prepare the entries of those vectors that are going to be used. auto builderIt = rewardModelBuilders.begin(); for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) { @@ -571,7 +602,7 @@ namespace storm { } else { // If the model is nondeterministic, we add all choices individually. transitionMatrixBuilder.newRowGroup(currentRow); - + auto builderIt = rewardModelBuilders.begin(); for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) { if (rewardModelIt->get().hasStateRewards()) { @@ -651,36 +682,7 @@ namespace storm { typename ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ModelComponents ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildModelComponents(storm::prism::Program const& program, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, Options const& options) { ModelComponents modelComponents; - uint_fast64_t bitOffset = 0; - VariableInformation variableInformation(program.getManager()); - for (auto const& booleanVariable : program.getGlobalBooleanVariables()) { - variableInformation.booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), bitOffset); - ++bitOffset; - variableInformation.booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = variableInformation.booleanVariables.size() - 1; - } - for (auto const& integerVariable : program.getGlobalIntegerVariables()) { - int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); - int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); - uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1))); - variableInformation.integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, bitOffset, bitwidth); - bitOffset += bitwidth; - variableInformation.integerVariableToIndexMap[integerVariable.getExpressionVariable()] = variableInformation.integerVariables.size() - 1; - } - for (auto const& module : program.getModules()) { - for (auto const& booleanVariable : module.getBooleanVariables()) { - variableInformation.booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), bitOffset); - ++bitOffset; - variableInformation.booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = variableInformation.booleanVariables.size() - 1; - } - for (auto const& integerVariable : module.getIntegerVariables()) { - int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); - int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); - uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1))); - variableInformation.integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, bitOffset, bitwidth); - bitOffset += bitwidth; - variableInformation.integerVariableToIndexMap[integerVariable.getExpressionVariable()] = variableInformation.integerVariables.size() - 1; - } - } + VariableInformation variableInformation(program); // Create the structure for storing the reachable state space. uint64_t bitsPerState = ((bitOffset / 64) + 1) * 64; diff --git a/src/builder/ExplicitPrismModelBuilder.h b/src/builder/ExplicitPrismModelBuilder.h index 5e4f5b2c5..21c45e30b 100644 --- a/src/builder/ExplicitPrismModelBuilder.h +++ b/src/builder/ExplicitPrismModelBuilder.h @@ -242,7 +242,7 @@ namespace storm { * @return A tuple containing a vector with all rows at which the nondeterministic choices of each state begin * and a vector containing the labels associated with each choice. */ - boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> buildMatrices(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, InternalStateInformation& internalStateInformation, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression); + boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> buildMatrices(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression); /*! * Explores the state space of the given program and returns the components of the model as a result. @@ -280,8 +280,9 @@ namespace storm { // successful build. boost::optional<StateInformation> stateInformation; - // A queue of states that still need to be explored. - std::queue<storm::storage::BitVector> statesToExplore; + // A queue of states that still need to be explored. The indices in this queue are the bucket indices in the + // bit vector hash map holding the compressed states. + std::queue<std::size_t> statesToExplore; }; diff --git a/src/generator/NextStateGenerator.h b/src/generator/NextStateGenerator.h index 8e8e4bbdb..4248ab90a 100644 --- a/src/generator/NextStateGenerator.h +++ b/src/generator/NextStateGenerator.h @@ -16,10 +16,10 @@ namespace storm { template<typename ValueType, typename StateType = uint32_t> class NextStateGenerator { public: - typedef StateType (*StateToIdCallback)(CompressedState const&); - - virtual std::vector<StateType> getInitialStates(StateToIdCallback stateToIdCallback) = 0; - virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback stateToIdCallback) = 0; + typedef std::function<StateType (CompressedState const&)> StateToIdCallback; + + virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) = 0; + virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) = 0; }; } } diff --git a/src/generator/PrismNextStateGenerator.cpp b/src/generator/PrismNextStateGenerator.cpp index a23ed29a6..602abb678 100644 --- a/src/generator/PrismNextStateGenerator.cpp +++ b/src/generator/PrismNextStateGenerator.cpp @@ -15,13 +15,108 @@ namespace storm { template<typename ValueType, typename StateType> void PrismNextStateGenerator<ValueType, StateType>::addRewardModel(storm::prism::RewardModel const& rewardModel) { selectedRewardModels.push_back(rewardModel); + hasStateActionRewards |= rewardModel.hasStateActionRewards(); } template<typename ValueType, typename StateType> - StateBehavior<ValueType, StateType> PrismNextStateGenerator<ValueType, StateType>::expand(CompressedState const& state, typename NextStateGenerator<ValueType, StateType>::StateToIdCallback stateToIdCallback) { - // TODO + std::vector<StateType> PrismNextStateGenerator<ValueType, StateType>::getInitialStates(StateToIdCallback const& stateToIdCallback) { + // FIXME, TODO, whatever } + template<typename ValueType, typename StateType> + StateBehavior<ValueType, StateType> PrismNextStateGenerator<ValueType, StateType>::expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) { + // Start by unpacking the state into the evaluator so we can quickly evaluate expressions later. + unpackStateIntoEvaluator(state); + + // Prepare the result, in case we return early. + StateBehavior<ValueType, StateType> result; + + // First, construct the state rewards, as we may return early if there are no choices later and we already + // need the state rewards then. + for (auto const& rewardModel : selectedRewardModels) { + ValueType stateReward = storm::utility::zero<ValueType>(); + if (rewardModel->hasStateRewards()) { + for (auto const& stateReward : rewardModel->getStateRewards()) { + if (evaluator.asBool(stateReward.getStatePredicateExpression())) { + stateReward += ValueType(evaluator.asRational(stateReward.getRewardValueExpression())); + } + } + } + result.addStateReward(stateReward); + } + + // Get all choices for the state. + std::vector<Choice<ValueType>> allChoices = getUnlabeledChoices(state, stateToIdCallback); + std::vector<Choice<ValueType>> allLabeledChoices = getLabeledChoices(state, stateToIdCallback); + for (auto& choice : allLabeledChoices) { + allChoices.push_back(std::move(choice)); + } + + std::size_t totalNumberOfChoices = allChoices.size(); + + // If there is not a single choice, we return immediately, because the state has no behavior (other than + // the state reward). + if (totalNumberOfChoices == 0) { + return result; + } + + // If the model is a deterministic model, we need to fuse the choices into one. + if (program.isDeterministicModel() && totalNumberOfChoices > 1) { + Choice<ValueType> globalChoice; + + // For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs + // this is equal to the number of choices, which is why we initialize it like this here. + ValueType totalExitRate = static_cast<ValueType>(totalNumberOfChoices); + + // Iterate over all choices and combine the probabilities/rates into one choice. + for (auto const& choice : allChoices) { + for (auto const& stateProbabilityPair : choice) { + if (program.isDiscreteTimeModel()) { + globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second / totalNumberOfChoices; + if (hasStateActionRewards) { + totalExitRate += choice.getTotalMass(); + } + } else { + globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second; + } + } + + if (buildChoiceLabeling) { + globalChoice.addChoiceLabels(choice.getChoiceLabels()); + } + } + + // Now construct the state-action reward for all selected reward models. + for (auto const& rewardModel : selectedRewardModels) { + ValueType stateActionReward = storm::utility::zero<ValueType>(); + if (rewardModel->hasStateActionRewards()) { + for (auto const& stateActionReward : rewardModel->getStateActionRewards()) { + for (auto const& choice : allChoices) { + if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) { + stateActionReward += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) / totalExitRate; + } + } + + } + } + globalChoice.addChoiceReward(stateActionReward); + } + + // Move the newly fused choice in place. + allChoices.clear(); + allChoices.push_back(std::move(globalChoice)); + } + + // Move all remaining choices in place. + for (auto& choice : allChoices) { + result.addChoice(std::move(choice)); + } + + return result; + } + + + template<typename ValueType, typename StateType> void PrismNextStateGenerator<ValueType, StateType>::unpackStateIntoEvaluator(storm::storage::BitVector const& state) { for (auto const& booleanVariable : variableInformation.booleanVariables) { @@ -31,7 +126,7 @@ namespace storm { evaluator.setIntegerValue(integerVariable.variable, state.getAsInt(integerVariable.bitOffset, integerVariable.bitWidth) + integerVariable.lowerBound); } } - + template<typename ValueType, typename StateType> CompressedState PrismNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::prism::Update const& update) { CompressedState newState(state); @@ -110,7 +205,7 @@ namespace storm { } template<typename ValueType, typename StateType> - std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getUnlabeledTransitions(CompressedState const& state, StateToIdCallback stateToIdCallback) { + std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getUnlabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback) { std::vector<Choice<ValueType>> result; // Iterate over all modules. @@ -129,7 +224,7 @@ namespace storm { continue; } - result.push_back(Choice<ValueType>(0, buildChoiceLabeling)); + result.push_back(Choice<ValueType>(command.getActionIndex())); Choice<ValueType>& choice = result.back(); // Remember the command labels only if we were asked to. @@ -152,6 +247,19 @@ namespace storm { probabilitySum += probability; } + // Create the state-action reward for the newly created choice. + for (auto const& rewardModel : selectedRewardModels) { + ValueType stateActionReward = storm::utility::zero<ValueType>(); + if (rewardModel->hasStateActionRewards()) { + for (auto const& stateActionReward : rewardModel->getStateActionRewards()) { + if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) { + stateActionReward += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass(); + } + } + } + choice.addChoiceReward(stateActionReward); + } + // Check that the resulting distribution is in fact a distribution. STORM_LOG_THROW(!program.isDiscreteTimeModel() || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for command '" << command << "' (actually sum to " << probabilitySum << ")."); } @@ -161,7 +269,7 @@ namespace storm { } template<typename ValueType, typename StateType> - std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getLabeledTransitions(CompressedState const& state, StateToIdCallback stateToIdCallback) { + std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getLabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback) { std::vector<Choice<ValueType>> result; for (uint_fast64_t actionIndex : program.getSynchronizingActionIndices()) { @@ -208,7 +316,7 @@ namespace storm { // At this point, we applied all commands of the current command combination and newTargetStates // contains all target states and their respective probabilities. That means we are now ready to // add the choice to the list of transitions. - result.push_back(Choice<ValueType>(actionIndex, buildChoiceLabeling)); + result.push_back(Choice<ValueType>(actionIndex)); // Now create the actual distribution. Choice<ValueType>& choice = result.back(); @@ -221,6 +329,7 @@ namespace storm { } } + // Add the probabilities/rates to the newly created choice. ValueType probabilitySum = storm::utility::zero<ValueType>(); for (auto const& stateProbabilityPair : *newTargetStates) { StateType actualIndex = stateToIdCallback(stateProbabilityPair.first); @@ -231,6 +340,19 @@ namespace storm { // Check that the resulting distribution is in fact a distribution. STORM_LOG_THROW(!program.isDiscreteTimeModel() || !comparator.isConstant(probabilitySum) || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not some to one for some command (actually sum to " << probabilitySum << ")."); + // Create the state-action reward for the newly created choice. + for (auto const& rewardModel : selectedRewardModels) { + ValueType stateActionReward = storm::utility::zero<ValueType>(); + if (rewardModel->hasStateActionRewards()) { + for (auto const& stateActionReward : rewardModel->getStateActionRewards()) { + if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) { + stateActionReward += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass(); + } + } + } + choice.addChoiceReward(stateActionReward); + } + // Dispose of the temporary maps. delete currentTargetStates; delete newTargetStates; diff --git a/src/generator/PrismNextStateGenerator.h b/src/generator/PrismNextStateGenerator.h index d3660ce05..282a2f25f 100644 --- a/src/generator/PrismNextStateGenerator.h +++ b/src/generator/PrismNextStateGenerator.h @@ -22,8 +22,8 @@ namespace storm { */ void addRewardModel(storm::prism::RewardModel const& rewardModel); - virtual std::vector<StateType> getInitialStates(StateToIdCallback stateToIdCallback) = 0; - virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback stateToIdCallback) override; + virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) override; + virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) override; private: /*! @@ -82,6 +82,9 @@ namespace storm { // The reward models that need to be considered. std::vector<std::reference_wrapper<storm::prism::RewardModel const>> selectedRewardModels; + // A flag that stores whether at least one of the selected reward models has state-action rewards. + bool hasStateActionRewards; + // A flag that stores whether or not to build the choice labeling. bool buildChoiceLabeling; diff --git a/src/generator/VariableInformation.cpp b/src/generator/VariableInformation.cpp index 7f7ed357e..bb20c5225 100644 --- a/src/generator/VariableInformation.cpp +++ b/src/generator/VariableInformation.cpp @@ -1,4 +1,4 @@ -#include "src/generator/prism/VariableInformation.h" +#include "src/generator/VariableInformation.h" #include "src/utility/macros.h" #include "src/exceptions/InvalidArgumentException.h" @@ -14,8 +14,39 @@ namespace storm { // Intentionally left empty. } - VariableInformation::VariableInformation(storm::expressions::ExpressionManager const& manager) : manager(manager) { - // Intentionally left empty. + VariableInformation::VariableInformation(storm::prism::Program const& program) : totalBitOffset(0) { + for (auto const& booleanVariable : program.getGlobalBooleanVariables()) { + booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), totalBitOffset); + ++totalBitOffset; + booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = booleanVariables.size() - 1; + } + for (auto const& integerVariable : program.getGlobalIntegerVariables()) { + int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); + int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); + uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1))); + integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, totalBitOffset, bitwidth); + totalBitOffset += bitwidth; + integerVariableToIndexMap[integerVariable.getExpressionVariable()] = integerVariables.size() - 1; + } + for (auto const& module : program.getModules()) { + for (auto const& booleanVariable : module.getBooleanVariables()) { + booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), totalBitOffset); + ++totalBitOffset; + booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = booleanVariables.size() - 1; + } + for (auto const& integerVariable : module.getIntegerVariables()) { + int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); + int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); + uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1))); + integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, totalBitOffset, bitwidth); + totalBitOffset += bitwidth; + integerVariableToIndexMap[integerVariable.getExpressionVariable()] = integerVariables.size() - 1; + } + } + } + + uint_fast64_t VariableInformation::getTotalBitOffset() const { + return totalBitOffset; } uint_fast64_t VariableInformation::getBitOffset(storm::expressions::Variable const& variable) const { diff --git a/src/generator/VariableInformation.h b/src/generator/VariableInformation.h index c1f06e741..a06156336 100644 --- a/src/generator/VariableInformation.h +++ b/src/generator/VariableInformation.h @@ -5,6 +5,7 @@ #include <boost/container/flat_map.hpp> #include "src/storage/expressions/Variable.h" +#include "src/storage/prism/Program.h" namespace storm { namespace generator { @@ -48,12 +49,16 @@ namespace storm { // A structure storing information about the used variables of the program. struct VariableInformation { - VariableInformation(storm::expressions::ExpressionManager const& manager); + VariableInformation(storm::prism::Program const& program); + uint_fast64_t getTotalBitOffset() const; // Provide methods to access the bit offset and width of variables in the compressed state. uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const; uint_fast64_t getBitWidth(storm::expressions::Variable const& variable) const; + // The total bit offset over all variables. + uint_fast64_t totalBitOffset; + // The known boolean variables. boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> booleanVariableToIndexMap; std::vector<BooleanVariableInformation> booleanVariables; @@ -61,8 +66,6 @@ namespace storm { // The known integer variables. boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> integerVariableToIndexMap; std::vector<IntegerVariableInformation> integerVariables; - - storm::expressions::ExpressionManager const& manager; }; } diff --git a/src/storage/BitVector.cpp b/src/storage/BitVector.cpp index cd5f46009..38b94d852 100644 --- a/src/storage/BitVector.cpp +++ b/src/storage/BitVector.cpp @@ -60,7 +60,7 @@ namespace storm { return currentIndex == other.currentIndex; } - BitVector::BitVector() : bitCount(0), bucketVector() { + BitVector::BitVector() : bitCount(0), buckets(nullptr) { // Intentionally left empty. } @@ -73,10 +73,17 @@ namespace storm { // Initialize the storage with the required values. if (init) { - bucketVector = std::vector<uint64_t>(bucketCount, -1ll); + buckets = new uint64_t[bucketCount]; + std::fill_n(buckets, bucketCount, -1ull); truncateLastBucket(); } else { - bucketVector = std::vector<uint64_t>(bucketCount, 0); + buckets = new uint64_t[bucketCount](); + } + } + + BitVector::~BitVector() { + if (buckets != nullptr) { + delete buckets; } } @@ -89,23 +96,22 @@ namespace storm { // Intentionally left empty. } - BitVector::BitVector(uint_fast64_t bucketCount, uint_fast64_t bitCount) : bitCount(bitCount), bucketVector(bucketCount) { + BitVector::BitVector(uint_fast64_t bucketCount, uint_fast64_t bitCount) : bitCount(bitCount) { STORM_LOG_ASSERT((bucketCount << 6) == bitCount, "Bit count does not match number of buckets."); + buckets = new uint64_t[bucketCount](); } - BitVector::BitVector(BitVector const& other) : bitCount(other.bitCount), bucketVector(other.bucketVector) { - // Intentionally left empty. + BitVector::BitVector(BitVector const& other) : bitCount(other.bitCount) { + buckets = new uint64_t[other.bucketCount()]; + std::copy_n(other.buckets, other.bucketCount(), buckets); } - //BitVector::BitVector(BitVector&& other) : bitCount(other.bitCount), bucketVector(std::move(other.bucketVector)) { - // Intentionally left empty. - //} - BitVector& BitVector::operator=(BitVector const& other) { // Only perform the assignment if the source and target are not identical. if (this != &other) { bitCount = other.bitCount; - bucketVector = std::vector<uint64_t>(other.bucketVector); + buckets = new uint64_t[other.bucketCount()]; + std::copy_n(other.buckets, other.bucketCount(), buckets); } return *this; } @@ -117,9 +123,9 @@ namespace storm { return false; } - std::vector<uint64_t>::const_iterator first1 = this->bucketVector.begin(); - std::vector<uint64_t>::const_iterator last1 = this->bucketVector.end(); - std::vector<uint64_t>::const_iterator first2 = other.bucketVector.begin(); + uint64_t* first1 = this->buckets; + uint64_t* last1 = this->buckets + this->bucketCount(); + uint64_t* first2 = other.buckets; for (; first1 != last1; ++first1, ++first2) { if (*first1 < *first2) { @@ -135,7 +141,8 @@ namespace storm { // Only perform the assignment if the source and target are not identical. if (this != &other) { bitCount = other.bitCount; - bucketVector = std::move(other.bucketVector); + this->buckets = other.buckets; + other.buckets = nullptr; } return *this; @@ -146,14 +153,7 @@ namespace storm { if (this->bitCount != other.bitCount) return false; // If the lengths match, we compare the buckets one by one. - for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it1 != bucketVector.end(); ++it1, ++it2) { - if (*it1 != *it2) { - return false; - } - } - - // All buckets were equal, so the bit vectors are equal. - return true; + return std::equal(this->buckets, this->buckets + this->bucketCount(), other.buckets); } bool BitVector::operator!=(BitVector const& other) const { @@ -166,9 +166,9 @@ namespace storm { uint64_t mask = 1ull << (63 - (index & mod64mask)); if (value) { - bucketVector[bucket] |= mask; + buckets[bucket] |= mask; } else { - bucketVector[bucket] &= ~mask; + buckets[bucket] &= ~mask; } } @@ -182,7 +182,7 @@ namespace storm { bool BitVector::operator[](uint_fast64_t index) const { uint64_t bucket = index >> 6; uint64_t mask = 1ull << (63 - (index & mod64mask)); - return (this->bucketVector[bucket] & mask) == mask; + return (this->buckets[bucket] & mask) == mask; } bool BitVector::get(uint_fast64_t index) const { @@ -197,89 +197,76 @@ namespace storm { ++newBucketCount; } - if (newBucketCount > bucketVector.size()) { + if (newBucketCount > this->bucketCount()) { + uint64_t* newBuckets = new uint64_t[newBucketCount]; + std::copy_n(buckets, this->bucketCount(), newBuckets); if (init) { - bucketVector.back() |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull); - bucketVector.resize(newBucketCount, -1ull); + newBuckets[this->bucketCount() - 1] |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull); + std::fill_n(newBuckets, newBucketCount - this->bucketCount(), -1ull); } else { - bucketVector.resize(newBucketCount, 0); + std::fill_n(newBuckets, newBucketCount - this->bucketCount(), 0); } + delete buckets; + buckets = newBuckets; bitCount = newLength; } else { // If the underlying storage does not need to grow, we have to insert the missing bits. if (init) { - bucketVector.back() |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull); + buckets[this->bucketCount() - 1] |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull); } bitCount = newLength; } truncateLastBucket(); } else { - bitCount = newLength; uint_fast64_t newBucketCount = newLength >> 6; if ((newLength & mod64mask) != 0) { ++newBucketCount; } - bucketVector.resize(newBucketCount); + // If the number of buckets needs to be reduced, we resize it now. Otherwise, we can just truncate the + // last bucket. + if (newBucketCount < this->bucketCount()) { + uint64_t* newBuckets = new uint64_t[newBucketCount]; + std::copy_n(buckets, newBucketCount, newBuckets); + delete buckets; + buckets = newBuckets; + bitCount = newLength; + } + bitCount = newLength; truncateLastBucket(); } } BitVector BitVector::operator&(BitVector const& other) const { STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match."); - BitVector result(bitCount); - std::vector<uint64_t>::iterator it = result.bucketVector.begin(); - for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) { - *it = *it1 & *it2; - } - + std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return a & b; }); return result; } BitVector& BitVector::operator&=(BitVector const& other) { STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match."); - - std::vector<uint64_t>::iterator it = bucketVector.begin(); - for (std::vector<uint64_t>::const_iterator otherIt = other.bucketVector.begin(); it != bucketVector.end() && otherIt != other.bucketVector.end(); ++it, ++otherIt) { - *it &= *otherIt; - } - + std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, this->buckets, [] (uint64_t const& a, uint64_t const& b) { return a & b; }); return *this; } BitVector BitVector::operator|(BitVector const& other) const { STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match."); - BitVector result(bitCount); - std::vector<uint64_t>::iterator it = result.bucketVector.begin(); - for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) { - *it = *it1 | *it2; - } - + std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return a | b; }); return result; } BitVector& BitVector::operator|=(BitVector const& other) { STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match."); - - std::vector<uint64_t>::iterator it = bucketVector.begin(); - for (std::vector<uint64_t>::const_iterator otherIt = other.bucketVector.begin(); it != bucketVector.end() && otherIt != other.bucketVector.end(); ++it, ++otherIt) { - *it |= *otherIt; - } - + std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, this->buckets, [] (uint64_t const& a, uint64_t const& b) { return a | b; }); return *this; } BitVector BitVector::operator^(BitVector const& other) const { STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match."); - BitVector result(bitCount); - std::vector<uint64_t>::iterator it = result.bucketVector.begin(); - for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) { - *it = *it1 ^ *it2; - } - + std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return a ^ b; }); result.truncateLastBucket(); return result; } @@ -314,19 +301,13 @@ namespace storm { BitVector BitVector::operator~() const { BitVector result(this->bitCount); - std::vector<uint64_t>::iterator it = result.bucketVector.begin(); - for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it) { - *it = ~(*it1); - } - + std::transform(this->buckets, this->buckets + this->bucketCount(), result.buckets, [] (uint64_t const& a) { return ~a; }); result.truncateLastBucket(); return result; } void BitVector::complement() { - for (auto& element : bucketVector) { - element = ~element; - } + std::transform(this->buckets, this->buckets + this->bucketCount(), this->buckets, [] (uint64_t const& a) { return ~a; }); truncateLastBucket(); } @@ -334,11 +315,7 @@ namespace storm { STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match."); BitVector result(bitCount); - std::vector<uint64_t>::iterator it = result.bucketVector.begin(); - for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) { - *it = ~(*it1) | *it2; - } - + std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return (~a | b); }); result.truncateLastBucket(); return result; } @@ -346,7 +323,11 @@ namespace storm { bool BitVector::isSubsetOf(BitVector const& other) const { STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match."); - for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it1 != bucketVector.end(); ++it1, ++it2) { + uint64_t const* it1 = buckets; + uint64_t const* ite1 = buckets + bucketCount(); + uint64_t const* it2 = other.buckets; + + for (; it1 != ite1; ++it1, ++it2) { if ((*it1 & *it2) != *it1) { return false; } @@ -357,7 +338,11 @@ namespace storm { bool BitVector::isDisjointFrom(BitVector const& other) const { STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match."); - for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it1 != bucketVector.end(); ++it1, ++it2) { + uint64_t const* it1 = buckets; + uint64_t const* ite1 = buckets + bucketCount(); + uint64_t const* it2 = other.buckets; + + for (; it1 != ite1; ++it1, ++it2) { if ((*it1 & *it2) != 0) { return false; } @@ -372,9 +357,9 @@ namespace storm { // Compute the first bucket that needs to be checked and the number of buckets. uint64_t index = bitIndex >> 6; - std::vector<uint64_t>::const_iterator first1 = bucketVector.begin() + index; - std::vector<uint64_t>::const_iterator first2 = other.bucketVector.begin(); - std::vector<uint64_t>::const_iterator last2 = other.bucketVector.end(); + uint64_t const* first1 = buckets + index; + uint64_t const* first2 = other.buckets; + uint64_t const* last2 = other.buckets + other.bucketCount(); for (; first2 != last2; ++first1, ++first2) { if (*first1 != *first2) { @@ -391,10 +376,10 @@ namespace storm { // Compute the first bucket that needs to be checked and the number of buckets. uint64_t index = bitIndex >> 6; - std::vector<uint64_t>::iterator first1 = bucketVector.begin() + index; - std::vector<uint64_t>::const_iterator first2 = other.bucketVector.begin(); - std::vector<uint64_t>::const_iterator last2 = other.bucketVector.end(); - + uint64_t* first1 = buckets + index; + uint64_t const* first2 = other.buckets; + uint64_t const* last2 = other.buckets + other.bucketCount(); + for (; first2 != last2; ++first1, ++first2) { *first1 = *first2; } @@ -406,8 +391,8 @@ namespace storm { STORM_LOG_ASSERT(index + numberOfBuckets <= this->bucketCount(), "Argument is out-of-range."); storm::storage::BitVector result(numberOfBuckets, numberOfBits); - std::copy(this->bucketVector.begin() + index, this->bucketVector.begin() + index + numberOfBuckets, result.bucketVector.begin()); - + std::copy(this->buckets + index, this->buckets + index + numberOfBuckets, result.buckets); + result.truncateLastBucket(); return result; } @@ -425,10 +410,10 @@ namespace storm { if (bitIndexInBucket + numberOfBits < 64) { // If the value stops before the end of the bucket, we need to erase some lower bits. mask &= ~((1ull << (64 - (bitIndexInBucket + numberOfBits))) - 1ull); - return (bucketVector[bucket] & mask) >> (64 - (bitIndexInBucket + numberOfBits)); + return (buckets[bucket] & mask) >> (64 - (bitIndexInBucket + numberOfBits)); } else if (bitIndexInBucket + numberOfBits > 64) { // In this case, the integer "crosses" the bucket line. - uint64_t result = (bucketVector[bucket] & mask); + uint64_t result = (buckets[bucket] & mask); ++bucket; // Compute the remaining number of bits. @@ -440,13 +425,13 @@ namespace storm { // Strip away everything from the second bucket that is beyond the final index and add it to the // intermediate result. mask = ~((1ull << (64 - numberOfBits)) - 1ull); - uint64_t lowerBits = bucketVector[bucket] & mask; + uint64_t lowerBits = buckets[bucket] & mask; result |= (lowerBits >> (64 - numberOfBits)); return result; } else { // In this case, it suffices to take the current mask. - return bucketVector[bucket] & mask; + return buckets[bucket] & mask; } } @@ -466,10 +451,10 @@ namespace storm { if (bitIndexInBucket + numberOfBits < 64) { // If the value stops before the end of the bucket, we need to erase some lower bits. mask &= ~((1ull << (64 - (bitIndexInBucket + numberOfBits))) - 1ull); - bucketVector[bucket] = (bucketVector[bucket] & ~mask) | (value << (64 - (bitIndexInBucket + numberOfBits))); + buckets[bucket] = (buckets[bucket] & ~mask) | (value << (64 - (bitIndexInBucket + numberOfBits))); } else if (bitIndexInBucket + numberOfBits > 64) { // Write the part of the value that falls into the first bucket. - bucketVector[bucket] = (bucketVector[bucket] & ~mask) | (value >> (numberOfBits + (bitIndexInBucket - 64))); + buckets[bucket] = (buckets[bucket] & ~mask) | (value >> (numberOfBits + (bitIndexInBucket - 64))); ++bucket; // Compute the remaining number of bits. @@ -480,45 +465,41 @@ namespace storm { // Put the remaining bits in their place. mask = ((1ull << (64 - numberOfBits)) - 1ull); - bucketVector[bucket] = (bucketVector[bucket] & mask) | value; + buckets[bucket] = (buckets[bucket] & mask) | value; } else { - bucketVector[bucket] = (bucketVector[bucket] & ~mask) | value; + buckets[bucket] = (buckets[bucket] & ~mask) | value; } } bool BitVector::empty() const { - for (auto& element : bucketVector) { - if (element != 0) { - return false; - } - } - return true; + uint64_t* last = buckets + bucketCount(); + uint64_t* it = std::find(buckets, last, 0); + return it != last; } bool BitVector::full() const { // Check that all buckets except the last one have all bits set. - for (uint_fast64_t index = 0; index < bucketVector.size() - 1; ++index) { - if (bucketVector[index] != -1ull) { + uint64_t* last = buckets + bucketCount() - 1; + for (uint64_t const* it = buckets; it != last; ++it) { + if (*it != -1ull) { return false; } } // Now check whether the relevant bits are set in the last bucket. uint64_t mask = ~((1ull << (64 - (bitCount & mod64mask))) - 1ull); - if ((bucketVector.back() & mask) != mask) { + if ((*last & mask) != mask) { return false; } return true; } void BitVector::clear() { - for (auto& element : bucketVector) { - element = 0; - } + std::fill_n(buckets, this->bucketCount(), 0); } uint_fast64_t BitVector::getNumberOfSetBits() const { - return getNumberOfSetBitsBeforeIndex(bucketVector.size() << 6); + return getNumberOfSetBitsBeforeIndex(bitCount); } uint_fast64_t BitVector::getNumberOfSetBitsBeforeIndex(uint_fast64_t index) const { @@ -529,14 +510,14 @@ namespace storm { for (uint_fast64_t i = 0; i < bucket; ++i) { // Check if we are using g++ or clang++ and, if so, use the built-in function #if (defined (__GNUG__) || defined(__clang__)) - result += __builtin_popcountll(bucketVector[i]); + result += __builtin_popcountll(buckets[i]); #elif defined WINDOWS #include <nmmintrin.h> // If the target machine does not support SSE4, this will fail. result += _mm_popcnt_u64(bucketVector[i]); #else uint_fast32_t cnt; - uint_fast64_t bitset = bucketVector[i]; + uint_fast64_t bitset = buckets[i]; for (cnt = 0; bitset; cnt++) { bitset &= bitset - 1; } @@ -548,7 +529,7 @@ namespace storm { uint64_t tmp = index & mod64mask; if (tmp != 0) { tmp = ~((1ll << (64 - (tmp & mod64mask))) - 1ll); - tmp &= bucketVector[bucket]; + tmp &= buckets[bucket]; // Check if we are using g++ or clang++ and, if so, use the built-in function #if (defined (__GNUG__) || defined(__clang__)) result += __builtin_popcountll(tmp); @@ -585,19 +566,19 @@ namespace storm { } std::size_t BitVector::getSizeInBytes() const { - return sizeof (*this) + sizeof (uint64_t) * bucketVector.size(); + return sizeof (*this) + sizeof (uint64_t) * bucketCount(); } BitVector::const_iterator BitVector::begin() const { - return const_iterator(bucketVector.data(), 0, bitCount); + return const_iterator(buckets, 0, bitCount); } BitVector::const_iterator BitVector::end() const { - return const_iterator(bucketVector.data(), bitCount, bitCount, false); + return const_iterator(buckets, bitCount, bitCount, false); } uint_fast64_t BitVector::getNextSetIndex(uint_fast64_t startingIndex) const { - return getNextSetIndex(bucketVector.data(), startingIndex, bitCount); + return getNextSetIndex(buckets, startingIndex, bitCount); } uint_fast64_t BitVector::getNextSetIndex(uint64_t const* dataPtr, uint_fast64_t startingIndex, uint_fast64_t endIndex) { @@ -641,17 +622,17 @@ namespace storm { void BitVector::truncateLastBucket() { if ((bitCount & mod64mask) != 0) { - bucketVector.back() &= ~((1ll << (64 - (bitCount & mod64mask))) - 1ll); + buckets[bucketCount() - 1] &= ~((1ll << (64 - (bitCount & mod64mask))) - 1ll); } } size_t BitVector::bucketCount() const { - return bucketVector.size(); + return bitCount >> 6; } - std::ostream& operator<<(std::ostream& out, BitVector const& bitVector) { - out << "bit vector(" << bitVector.getNumberOfSetBits() << "/" << bitVector.bitCount << ") ["; - for (auto index : bitVector) { + std::ostream& operator<<(std::ostream& out, BitVector const& bitvector) { + out << "bit vector(" << bitvector.getNumberOfSetBits() << "/" << bitvector.bitCount << ") ["; + for (auto index : bitvector) { out << index << " "; } out << "]"; @@ -659,13 +640,13 @@ namespace storm { return out; } - std::size_t NonZeroBitVectorHash::operator()(storm::storage::BitVector const& bv) const { - STORM_LOG_ASSERT(bv.size() > 0, "Cannot hash bit vector of zero size."); + std::size_t NonZeroBitVectorHash::operator()(storm::storage::BitVector const& bitvector) const { + STORM_LOG_ASSERT(bitvector.size() > 0, "Cannot hash bit vector of zero size."); std::size_t result = 0; - for (uint_fast64_t index = 0; index < bv.bucketVector.size(); ++index) { + for (uint_fast64_t index = 0; index < bitvector.bucketCount(); ++index) { result ^= result << 3; - result ^= result >> bv.getAsInt(index << 6, 5); + result ^= result >> bitvector.getAsInt(index << 6, 5); } // Erase the last bit and add one to definitely make this hash value non-zero. diff --git a/src/storage/BitVector.h b/src/storage/BitVector.h index f9c088ceb..a6ad89cc3 100644 --- a/src/storage/BitVector.h +++ b/src/storage/BitVector.h @@ -104,6 +104,11 @@ namespace storm { */ BitVector(); + /* + * Deconstructs a bit vector by deleting the underlying storage. + */ + ~BitVector(); + /*! * Constructs a bit vector which can hold the given number of bits and initializes all bits with the * provided truth value. @@ -494,7 +499,7 @@ namespace storm { uint_fast64_t bitCount; // The underlying storage of 64-bit buckets for all bits of this bit vector. - std::vector<uint64_t> bucketVector; + uint64_t* buckets; // A bit mask that can be used to reduce a modulo 64 operation to a logical "and". static const uint_fast64_t mod64mask = (1 << 6) - 1; From 9eec5b140c88d6d6ae180d22854676b06329a274 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Thu, 25 Feb 2016 18:27:23 +0100 Subject: [PATCH 05/33] refactoring of model builder Former-commit-id: f049f5a5bf4d759caae6a037cc12ca5ae56bfda0 --- src/builder/ExplicitPrismModelBuilder.cpp | 394 ++++------------------ src/builder/ExplicitPrismModelBuilder.h | 18 +- src/generator/Choice.cpp | 5 + src/generator/Choice.h | 5 + src/generator/CompressedState.cpp | 22 ++ src/generator/CompressedState.h | 30 ++ src/generator/NextStateGenerator.h | 9 +- src/generator/PrismNextStateGenerator.cpp | 49 ++- src/generator/PrismNextStateGenerator.h | 18 +- src/generator/StateBehavior.cpp | 35 ++ src/generator/StateBehavior.h | 38 +++ src/generator/VariableInformation.h | 6 +- 12 files changed, 264 insertions(+), 365 deletions(-) create mode 100644 src/generator/CompressedState.cpp create mode 100644 src/generator/CompressedState.h diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp index 4a777c6f9..232d7f263 100644 --- a/src/builder/ExplicitPrismModelBuilder.cpp +++ b/src/builder/ExplicitPrismModelBuilder.cpp @@ -14,6 +14,7 @@ #include "src/generator/PrismNextStateGenerator.h" #include "src/utility/prism.h" +#include "src/utility/constants.h" #include "src/utility/macros.h" #include "src/utility/ConstantsComparator.h" #include "src/exceptions/WrongFormatException.h" @@ -29,7 +30,7 @@ namespace storm { template <typename ValueType> struct RewardModelBuilder { public: - RewardModelBuilder(bool deterministicModel, bool hasStateRewards, bool hasStateActionRewards, bool hasTransitionRewards) : hasStateRewards(hasStateRewards), hasStateActionRewards(hasStateActionRewards), hasTransitionRewards(hasTransitionRewards), stateRewardVector(), stateActionRewardVector(), transitionRewardMatrixBuilder(0, 0, 0, false, !deterministicModel, 0) { + RewardModelBuilder(bool deterministicModel, bool hasStateRewards, bool hasStateActionRewards, bool hasTransitionRewards) : hasStateRewards(hasStateRewards), hasStateActionRewards(hasStateActionRewards), hasTransitionRewards(hasTransitionRewards), stateRewardVector(), stateActionRewardVector() { // Intentionally left empty. } @@ -46,12 +47,7 @@ namespace storm { optionalStateActionRewardVector = std::move(stateActionRewardVector); } - boost::optional<storm::storage::SparseMatrix<ValueType>> optionalTransitionRewardMatrix; - if (hasTransitionRewards) { - optionalTransitionRewardMatrix = transitionRewardMatrixBuilder.build(rowCount, columnCount, rowGroupCount); - } - - return storm::models::sparse::StandardRewardModel<ValueType>(std::move(optionalStateRewardVector), std::move(optionalStateActionRewardVector), std::move(optionalTransitionRewardMatrix)); + return storm::models::sparse::StandardRewardModel<ValueType>(std::move(optionalStateRewardVector), std::move(optionalStateActionRewardVector)); } bool hasStateRewards; @@ -63,9 +59,6 @@ namespace storm { // The state-action reward vector. std::vector<ValueType> stateActionRewardVector; - - // A builder that is used for constructing the transition reward matrix. - storm::storage::SparseMatrixBuilder<ValueType> transitionRewardMatrixBuilder; }; template <typename ValueType, typename RewardModelType, typename StateType> @@ -182,7 +175,7 @@ namespace storm { } template <typename ValueType, typename RewardModelType, typename StateType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ExplicitPrismModelBuilder(storm::prism::Program const& program, Options const& options) : options(options), program(program), variableInformation(program), internalStateInformation(variableInformation.getTotalBitOffset()) { + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ExplicitPrismModelBuilder(storm::prism::Program const& program, Options const& options) : program(program), options(options), variableInformation(program), internalStateInformation(variableInformation.getTotalBitOffset()) { // Start by defining the undefined constants in the model. if (options.constantDefinitions) { this->program = program.defineUndefinedConstants(options.constantDefinitions.get()); @@ -248,7 +241,7 @@ namespace storm { template <typename ValueType, typename RewardModelType, typename StateType> std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::translate() { - STORM_LOG_DEBUG("Building representation of program:" << std::endl << *program << std::endl); + STORM_LOG_DEBUG("Building representation of program:" << std::endl << program << std::endl); // Select the appropriate reward models (after the constants have been substituted). std::vector<std::reference_wrapper<storm::prism::RewardModel const>> selectedRewardModels; @@ -269,7 +262,7 @@ namespace storm { selectedRewardModels.push_back(program.getRewardModel(0)); } - ModelComponents modelComponents = buildModelComponents(*program, selectedRewardModels, options); + ModelComponents modelComponents = buildModelComponents(selectedRewardModels); std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> result; switch (program.getModelType()) { @@ -304,13 +297,13 @@ namespace storm { template <typename ValueType, typename RewardModelType, typename StateType> StateType ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex(CompressedState const& state) { - uint32_t newIndex = internalStateInformation.reachableStates.size(); + uint32_t newIndex = internalStateInformation.numberOfStates; // Check, if the state was already registered. std::pair<uint32_t, std::size_t> actualIndexBucketPair = internalStateInformation.stateStorage.findOrAddAndGetBucket(state, newIndex); if (actualIndexBucketPair.first == newIndex) { - statesToExplore.push(state); + statesToExplore.push_back(state); ++internalStateInformation.numberOfStates; } @@ -327,12 +320,15 @@ namespace storm { // Create a generator that is able to expand states. storm::generator::PrismNextStateGenerator<ValueType, StateType> generator(program, variableInformation, options.buildCommandLabels); + if (terminalExpression) { + generator.setTerminalExpression(terminalExpression.get()); + } for (auto const& rewardModel : selectedRewardModels) { generator.addRewardModel(rewardModel.get()); } // Create a callback for the next-state generator to enable it to request the index of states. - std::function<StateType (CompressedState const&)> stateToIdCallback = std::bind1st(&ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex, this); + std::function<StateType (CompressedState const&)> stateToIdCallback = std::bind(&ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex, this, std::placeholders::_1); // Let the generator create all initial states. generator.getInitialStates(stateToIdCallback); @@ -340,358 +336,108 @@ namespace storm { // Now explore the current state until there is no more reachable state. uint_fast64_t currentRow = 0; - // Perform a DFS through the model. + // Perform a search through the model. while (!statesToExplore.empty()) { // Get the first state in the queue. - std::pair<CompressedState, StateType> currentState = internalStateInformation.stateStorage.getBucketAndValue(statesToExplore.front()); - statesToExplore.pop(); - - STORM_LOG_TRACE("Exploring state with id " << currentState.second << "."); - - bool deadlockOnPurpose = false; - if (terminalExpression && evaluator.asBool(terminalExpression.get())) { - // Nothing to do in this case. - deadlockOnPurpose = true; - } else { - // Retrieve all choices for the current state. - allUnlabeledChoices = getUnlabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator); - allLabeledChoices = getLabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator); - } - - - } - - - - - - // Initialize a queue and insert the initial state. - std::queue<storm::storage::BitVector> stateQueue; - CompressedState initialState(internalStateInformation.bitsPerState); - - // We need to initialize the values of the variables to their initial value. - for (auto const& booleanVariable : variableInformation.booleanVariables) { - initialState.set(booleanVariable.bitOffset, booleanVariable.initialValue); - } - for (auto const& integerVariable : variableInformation.integerVariables) { - initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast<uint_fast64_t>(integerVariable.initialValue - integerVariable.lowerBound)); - } - - // At this point, we determine whether there are reward models with state-action rewards, because we might - // want to know that quickly later on. - bool hasStateActionRewards = false; - for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt) { - if (rewardModelIt->get().hasStateActionRewards()) { - hasStateActionRewards = true; - break; - } - } - - // Insert the initial state in the global state to index mapping and state queue. - uint32_t stateIndex = getOrAddStateIndex(initialState, internalStateInformation, stateQueue); - internalStateInformation.initialStateIndices.push_back(stateIndex); - - // Now explore the current state until there is no more reachable state. - uint_fast64_t currentRow = 0; - - // The evaluator used to determine the truth value of guards and predicates in the *current* state. - storm::expressions::ExpressionEvaluator<ValueType> evaluator(program.getManager()); - - // Perform a BFS through the model. - while (!stateQueue.empty()) { - // Get the current state and unpack it. - storm::storage::BitVector currentState = stateQueue.front(); - stateQueue.pop(); - StateType stateIndex = internalStateInformation.stateStorage.getValue(currentState); - STORM_LOG_TRACE("Exploring state with id " << stateIndex << "."); - unpackStateIntoEvaluator(currentState, variableInformation, evaluator); + CompressedState currentState = statesToExplore.front(); + StateType currentIndex = internalStateInformation.stateStorage.getValue(currentState); + statesToExplore.pop_front(); - // If a terminal expression was given, we check whether the current state needs to be explored further. - std::vector<Choice<ValueType>> allUnlabeledChoices; - std::vector<Choice<ValueType>> allLabeledChoices; - bool deadlockOnPurpose = false; - if (terminalExpression && evaluator.asBool(terminalExpression.get())) { - // Nothing to do in this case. - deadlockOnPurpose = true; - } else { - // Retrieve all choices for the current state. - allUnlabeledChoices = getUnlabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator); - allLabeledChoices = getLabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator); - } + STORM_LOG_TRACE("Exploring state with id " << index << "."); - uint_fast64_t totalNumberOfChoices = allUnlabeledChoices.size() + allLabeledChoices.size(); + storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(currentState, stateToIdCallback); - // If the current state does not have a single choice, we equip it with a self-loop if that was - // requested and issue an error otherwise. - if (totalNumberOfChoices == 0) { - if (!storm::settings::generalSettings().isDontFixDeadlocksSet() || deadlockOnPurpose) { - if (commandLabels) { + // If there is no behavior, we might have to introduce a self-loop. + if (behavior.empty()) { + if (!storm::settings::generalSettings().isDontFixDeadlocksSet() || !behavior.wasExpanded()) { + if (options.buildCommandLabels) { // Insert empty choice labeling for added self-loop transitions. choiceLabels.get().push_back(boost::container::flat_set<uint_fast64_t>()); } - if (!deterministicModel) { + if (!generator.isDeterministicModel()) { transitionMatrixBuilder.newRowGroup(currentRow); } - transitionMatrixBuilder.addNextValue(currentRow, stateIndex, storm::utility::one<ValueType>()); + transitionMatrixBuilder.addNextValue(currentRow, currentIndex, storm::utility::one<ValueType>()); auto builderIt = rewardModelBuilders.begin(); - for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) { - if (rewardModelIt->get().hasStateRewards()) { + for (auto const& rewardModel : selectedRewardModels) { + if (rewardModel.get().hasStateRewards()) { builderIt->stateRewardVector.push_back(storm::utility::zero<ValueType>()); } - if (rewardModelIt->get().hasStateActionRewards()) { + if (rewardModel.get().hasStateActionRewards()) { builderIt->stateActionRewardVector.push_back(storm::utility::zero<ValueType>()); } + ++builderIt; } ++currentRow; } else { - std::cout << unpackStateIntoValuation(currentState, variableInformation).toString(true) << std::endl; + std::cout << unpackStateIntoValuation(currentState).toString(true) << std::endl; STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Error while creating sparse matrix from probabilistic program: found deadlock state. For fixing these, please provide the appropriate option."); - } - } else if (totalNumberOfChoices == 1) { - if (!deterministicModel) { - transitionMatrixBuilder.newRowGroup(currentRow); - } - - bool labeledChoice = allUnlabeledChoices.empty() ? true : false; - Choice<ValueType> const& globalChoice = labeledChoice ? allLabeledChoices.front() : allUnlabeledChoices.front(); - + } else { + // Add the state rewards to the corresponding reward models. auto builderIt = rewardModelBuilders.begin(); - for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) { - if (rewardModelIt->get().hasStateRewards()) { - builderIt->stateRewardVector.push_back(storm::utility::zero<ValueType>()); - for (auto const& stateReward : rewardModelIt->get().getStateRewards()) { - if (evaluator.asBool(stateReward.getStatePredicateExpression())) { - builderIt->stateRewardVector.back() += ValueType(evaluator.asRational(stateReward.getRewardValueExpression())); - } - } - } - - if (rewardModelIt->get().hasStateActionRewards()) { - builderIt->stateActionRewardVector.push_back(storm::utility::zero<ValueType>()); - for (auto const& stateActionReward : rewardModelIt->get().getStateActionRewards()) { - if ((labeledChoice && stateActionReward.isLabeled() && stateActionReward.getActionIndex() == globalChoice.getActionIndex()) || (!labeledChoice && !stateActionReward.isLabeled())) { - if (evaluator.asBool(stateActionReward.getStatePredicateExpression())) { - builderIt->stateActionRewardVector.back() += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())); - } - } - } + auto stateRewardIt = behavior.getStateRewards().begin(); + for (auto const& rewardModel : selectedRewardModels) { + if (rewardModel.get().hasStateRewards()) { + builderIt->stateRewardVector.push_back(*stateRewardIt); } + ++stateRewardIt; + ++builderIt; } - for (auto const& stateProbabilityPair : globalChoice) { - transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second); - } - - if (commandLabels) { - // Now add the resulting distribution as the only choice of the current state. - choiceLabels.get().push_back(globalChoice.getChoiceLabels()); + // If the model is nondeterministic, we need to open a row group. + if (!generator.isDeterministicModel()) { + transitionMatrixBuilder.newRowGroup(currentRow); } - ++currentRow; - } else { - // Then, based on whether the model is deterministic or not, either add the choices individually - // or compose them to one choice. - if (deterministicModel) { - Choice<ValueType> globalChoice; - - // We need to prepare the entries of those vectors that are going to be used. - auto builderIt = rewardModelBuilders.begin(); - for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) { - if (rewardModelIt->get().hasStateRewards()) { - builderIt->stateRewardVector.push_back(storm::utility::zero<ValueType>()); - for (auto const& stateReward : rewardModelIt->get().getStateRewards()) { - if (evaluator.asBool(stateReward.getStatePredicateExpression())) { - builderIt->stateRewardVector.back() += ValueType(evaluator.asRational(stateReward.getRewardValueExpression())); - } - } - } - - if (rewardModelIt->get().hasStateActionRewards()) { - builderIt->stateActionRewardVector.push_back(storm::utility::zero<ValueType>()); - } - } - - // If there is one state-action reward model, we need to scale the rewards according to the - // multiple choices. - ValueType totalExitMass = storm::utility::zero<ValueType>(); - if (hasStateActionRewards) { - if (discreteTimeModel) { - totalExitMass = static_cast<ValueType>(totalNumberOfChoices); - } else { - // In the CTMC, we need to compute the exit rate of the state here, sin - for (auto const& choice : allUnlabeledChoices) { - totalExitMass += choice.getTotalMass(); - } - for (auto const& choice : allLabeledChoices) { - totalExitMass += choice.getTotalMass(); - } - } - } - - // Combine all the choices and scale them with the total number of choices of the current state. - for (auto const& choice : allUnlabeledChoices) { - if (commandLabels) { - globalChoice.addChoiceLabels(choice.getChoiceLabels()); - } - - auto builderIt = rewardModelBuilders.begin(); - for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) { - if (rewardModelIt->get().hasStateActionRewards()) { - for (auto const& stateActionReward : rewardModelIt->get().getStateActionRewards()) { - if (!stateActionReward.isLabeled()) { - if (evaluator.asBool(stateActionReward.getStatePredicateExpression())) { - builderIt->stateActionRewardVector.back() += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass() / totalExitMass; - } - } - } - } - } - - for (auto const& stateProbabilityPair : choice) { - if (discreteTimeModel) { - globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second / totalNumberOfChoices; - } else { - globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second; - } - } - } - for (auto const& choice : allLabeledChoices) { - if (commandLabels) { - globalChoice.addChoiceLabels(choice.getChoiceLabels()); - } - - auto builderIt = rewardModelBuilders.begin(); - for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) { - if (rewardModelIt->get().hasStateActionRewards()) { - for (auto const& stateActionReward : rewardModelIt->get().getStateActionRewards()) { - if (stateActionReward.isLabeled() && stateActionReward.getActionIndex() == choice.getActionIndex()) { - if (evaluator.asBool(stateActionReward.getStatePredicateExpression())) { - builderIt->stateActionRewardVector.back() += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass() / totalExitMass; - } - } - } - } - } - - for (auto const& stateProbabilityPair : choice) { - if (discreteTimeModel) { - globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second / totalNumberOfChoices; - } else { - globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second; - } - } + // Now add all choices. + for (auto const& choice : behavior) { + // Add command labels if requested. + if (options.buildCommandLabels) { + choiceLabels.get().push_back(choice.getChoiceLabels()); } - - if (commandLabels) { - // Now add the resulting distribution as the only choice of the current state. - choiceLabels.get().push_back(globalChoice.getChoiceLabels()); - } - - for (auto const& stateProbabilityPair : globalChoice) { + // Add the probabilistic behavior to the matrix. + for (auto const& stateProbabilityPair : behavior) { transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second); } - ++currentRow; - } else { - // If the model is nondeterministic, we add all choices individually. - transitionMatrixBuilder.newRowGroup(currentRow); - + // Add the rewards to the reward models. auto builderIt = rewardModelBuilders.begin(); - for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) { - if (rewardModelIt->get().hasStateRewards()) { - builderIt->stateRewardVector.push_back(storm::utility::zero<ValueType>()); - - for (auto const& stateReward : rewardModelIt->get().getStateRewards()) { - if (evaluator.asBool(stateReward.getStatePredicateExpression())) { - builderIt->stateRewardVector.back() += ValueType(evaluator.asRational(stateReward.getRewardValueExpression())); - } - } + auto choiceRewardIt = behavior.getChoiceRewards().begin(); + for (auto const& rewardModel : selectedRewardModels) { + if (rewardModel.get().hasStateActionRewards()) { + builderIt->stateActionRewardVector.push_back(*choiceRewardIt); } + ++choiceRewardIt; + ++builderIt; } - // First, process all unlabeled choices. - for (auto const& choice : allUnlabeledChoices) { - std::map<uint_fast64_t, ValueType> stateToRewardMap; - if (commandLabels) { - choiceLabels.get().emplace_back(std::move(choice.getChoiceLabels())); - } - - auto builderIt = rewardModelBuilders.begin(); - for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) { - if (rewardModelIt->get().hasStateActionRewards()) { - builderIt->stateActionRewardVector.push_back(storm::utility::zero<ValueType>()); - for (auto const& stateActionReward : rewardModelIt->get().getStateActionRewards()) { - if (!stateActionReward.isLabeled()) { - if (evaluator.asBool(stateActionReward.getStatePredicateExpression())) { - builderIt->stateActionRewardVector.back() += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())); - } - } - } - } - } - - for (auto const& stateProbabilityPair : choice) { - transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second); - } - - ++currentRow; - } - - // Then, process all labeled choices. - for (auto const& choice : allLabeledChoices) { - std::map<uint_fast64_t, ValueType> stateToRewardMap; - if (commandLabels) { - choiceLabels.get().emplace_back(std::move(choice.getChoiceLabels())); - } - - auto builderIt = rewardModelBuilders.begin(); - for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) { - if (rewardModelIt->get().hasStateActionRewards()) { - builderIt->stateActionRewardVector.push_back(storm::utility::zero<ValueType>()); - for (auto const& stateActionReward : rewardModelIt->get().getStateActionRewards()) { - if (stateActionReward.isLabeled() && stateActionReward.getActionIndex() == choice.getActionIndex()) { - if (evaluator.asBool(stateActionReward.getStatePredicateExpression())) { - builderIt->stateActionRewardVector.back() += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())); - } - } - } - } - } - - for (auto const& stateProbabilityPair : choice) { - transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second); - } - - ++currentRow; - } + ++currentRow; } } } - + return choiceLabels; } template <typename ValueType, typename RewardModelType, typename StateType> - typename ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ModelComponents ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildModelComponents(storm::prism::Program const& program, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, Options const& options) { + typename ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ModelComponents ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildModelComponents(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels) { ModelComponents modelComponents; - VariableInformation variableInformation(program); - // Create the structure for storing the reachable state space. - uint64_t bitsPerState = ((bitOffset / 64) + 1) * 64; + uint64_t bitsPerState = ((variableInformation.getTotalBitOffset() / 64) + 1) * 64; InternalStateInformation internalStateInformation(bitsPerState); // Determine whether we have to combine different choices to one or whether this model can have more than // one choice per state. - bool deterministicModel = program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::CTMC; - bool discreteTimeModel = program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::MDP; + bool deterministicModel = program.isDeterministicModel(); + bool discreteTimeModel = program.isDiscreteTimeModel(); // Prepare the transition matrix builder and the reward model builders. storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0); @@ -741,13 +487,13 @@ namespace storm { } // Build the state labeling. - modelComponents.stateLabeling = buildStateLabeling(program, variableInformation, internalStateInformation); + modelComponents.stateLabeling = buildStateLabeling(); // Finally -- if requested -- build the state information that can be retrieved from the outside. if (options.buildStateInformation) { - stateInformation = StateInformation(internalStateInformation.reachableStates.size()); + stateInformation = StateInformation(internalStateInformation.numberOfStates); for (auto const& bitVectorIndexPair : internalStateInformation.stateStorage) { - stateInformation.get().valuations[bitVectorIndexPair.second] = unpackStateIntoValuation(bitVectorIndexPair.first, variableInformation); + stateInformation.get().valuations[bitVectorIndexPair.second] = unpackStateIntoValuation(bitVectorIndexPair.first); } } @@ -755,23 +501,23 @@ namespace storm { } template <typename ValueType, typename RewardModelType, typename StateType> - storm::models::sparse::StateLabeling ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildStateLabeling(storm::prism::Program const& program, VariableInformation const& variableInformation, InternalStateInformation const& internalStateInformation) { - storm::expressions::ExpressionEvaluator<ValueType> evaluator(program.getManager()); - + storm::models::sparse::StateLabeling ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildStateLabeling() { std::vector<storm::prism::Label> const& labels = program.getLabels(); - storm::models::sparse::StateLabeling result(internalStateInformation.reachableStates.size()); + storm::expressions::ExpressionEvaluator<ValueType> evaluator(program.getManager()); + storm::models::sparse::StateLabeling result(internalStateInformation.numberOfStates); // Initialize labeling. for (auto const& label : labels) { result.addLabel(label.getName()); } - for (uint_fast64_t index = 0; index < internalStateInformation.reachableStates.size(); index++) { - unpackStateIntoEvaluator(internalStateInformation.reachableStates[index], variableInformation, evaluator); + for (auto const& stateIndexPair : internalStateInformation.stateStorage) { + unpackStateIntoEvaluator(stateIndexPair.first, variableInformation, evaluator); + for (auto const& label : labels) { // Add label to state, if the corresponding expression is true. if (evaluator.asBool(label.getStatePredicateExpression())) { - result.addLabelToState(label.getName(), index); + result.addLabelToState(label.getName(), stateIndexPair.second); } } } diff --git a/src/builder/ExplicitPrismModelBuilder.h b/src/builder/ExplicitPrismModelBuilder.h index 21c45e30b..54fe9cf30 100644 --- a/src/builder/ExplicitPrismModelBuilder.h +++ b/src/builder/ExplicitPrismModelBuilder.h @@ -4,7 +4,7 @@ #include <memory> #include <utility> #include <vector> -#include <queue> +#include <deque> #include <cstdint> #include <boost/functional/hash.hpp> #include <boost/container/flat_set.hpp> @@ -22,9 +22,9 @@ #include "src/storage/SparseMatrix.h" #include "src/settings/SettingsManager.h" - #include "src/utility/prism.h" +#include "src/generator/CompressedState.h" #include "src/generator/VariableInformation.h" namespace storm { @@ -35,6 +35,7 @@ namespace storm { namespace builder { using namespace storm::utility::prism; + using namespace storm::generator; // Forward-declare classes. template <typename ValueType> struct RewardModelBuilder; @@ -42,8 +43,6 @@ namespace storm { template<typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>, typename StateType = uint32_t> class ExplicitPrismModelBuilder { public: - typedef storm::storage::BitVector CompressedState; - // A structure holding information about the reachable state space while building it. struct InternalStateInformation { InternalStateInformation(uint64_t bitsPerState); @@ -271,7 +270,7 @@ namespace storm { Options options; // The variable information. - storm::generator::VariableInformation variableInformation; + VariableInformation variableInformation; // Internal information about the states that were explored. InternalStateInformation internalStateInformation; @@ -280,9 +279,12 @@ namespace storm { // successful build. boost::optional<StateInformation> stateInformation; - // A queue of states that still need to be explored. The indices in this queue are the bucket indices in the - // bit vector hash map holding the compressed states. - std::queue<std::size_t> statesToExplore; + // A set of states that still need to be explored. + std::deque<CompressedState> statesToExplore; + + // An optional mapping from row groups to the indices of the states that they reflect. This needs to be built + // in case the exploration order is not BFS. +// boost::optional<std::vector<StateType, StateType>> rowGroupToIndexMapping; }; diff --git a/src/generator/Choice.cpp b/src/generator/Choice.cpp index 8f42b7b3a..f80831ca0 100644 --- a/src/generator/Choice.cpp +++ b/src/generator/Choice.cpp @@ -92,6 +92,11 @@ namespace storm { choiceRewards.push_back(value); } + template<typename ValueType, typename StateType> + std::vector<ValueType> const& Choice<ValueType, StateType>::getChoiceRewards() const { + return choiceRewards; + } + template<typename ValueType, typename StateType> std::size_t Choice<ValueType, StateType>::size() const { return distribution.size(); diff --git a/src/generator/Choice.h b/src/generator/Choice.h index 78287d62e..95810bfb2 100644 --- a/src/generator/Choice.h +++ b/src/generator/Choice.h @@ -124,6 +124,11 @@ namespace storm { */ void addChoiceReward(ValueType const& value); + /*! + * Retrieves the rewards for this choice under selected reward models. + */ + std::vector<ValueType> const& getChoiceRewards() const; + /*! * Retrieves the size of the distribution associated with this choice. */ diff --git a/src/generator/CompressedState.cpp b/src/generator/CompressedState.cpp new file mode 100644 index 000000000..1f71d2407 --- /dev/null +++ b/src/generator/CompressedState.cpp @@ -0,0 +1,22 @@ +#include "src/generator/CompressedState.h" + +#include "src/generator/VariableInformation.h" +#include "src/storage/expressions/ExpressionEvaluator.h" + +namespace storm { + namespace generator { + + template<typename ValueType> + static void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator) { + for (auto const& booleanVariable : variableInformation.booleanVariables) { + evaluator.setBooleanValue(booleanVariable.variable, state.get(booleanVariable.bitOffset)); + } + for (auto const& integerVariable : variableInformation.integerVariables) { + evaluator.setIntegerValue(integerVariable.variable, state.getAsInt(integerVariable.bitOffset, integerVariable.bitWidth) + integerVariable.lowerBound); + } + + } + + + } +} \ No newline at end of file diff --git a/src/generator/CompressedState.h b/src/generator/CompressedState.h new file mode 100644 index 000000000..512db591f --- /dev/null +++ b/src/generator/CompressedState.h @@ -0,0 +1,30 @@ +#ifndef STORM_GENERATOR_COMPRESSEDSTATE_H_ +#define STORM_GENERATOR_COMPRESSEDSTATE_H_ + +#include "src/storage/BitVector.h" + +namespace storm { + namespace expressions { + template<typename ValueType> class ExpressionEvaluator; + } + + namespace generator { + + typedef storm::storage::BitVector CompressedState; + + class VariableInformation; + + /*! + * Unpacks the compressed state into the evaluator. + * + * @param state The state to unpack. + * @param variableInformation The information about how the variables are packed with the state. + * @param evaluator The evaluator into which to load the state. + */ + template<typename ValueType> + static void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator); + } +} + +#endif /* STORM_GENERATOR_COMPRESSEDSTATE_H_ */ + diff --git a/src/generator/NextStateGenerator.h b/src/generator/NextStateGenerator.h index 4248ab90a..f70709779 100644 --- a/src/generator/NextStateGenerator.h +++ b/src/generator/NextStateGenerator.h @@ -4,20 +4,17 @@ #include <vector> #include <cstdint> -#include "src/storage/sparse/StateType.h" -#include "src/storage/BitVector.h" - +#include "src/generator/CompressedState.h" #include "src/generator/StateBehavior.h" namespace storm { namespace generator { - typedef storm::storage::BitVector CompressedState; - template<typename ValueType, typename StateType = uint32_t> class NextStateGenerator { public: typedef std::function<StateType (CompressedState const&)> StateToIdCallback; - + + virtual bool isDeterministicModel() const = 0; virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) = 0; virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) = 0; }; diff --git a/src/generator/PrismNextStateGenerator.cpp b/src/generator/PrismNextStateGenerator.cpp index 602abb678..f8243998f 100644 --- a/src/generator/PrismNextStateGenerator.cpp +++ b/src/generator/PrismNextStateGenerator.cpp @@ -18,16 +18,39 @@ namespace storm { hasStateActionRewards |= rewardModel.hasStateActionRewards(); } + template<typename ValueType, typename StateType> + void PrismNextStateGenerator<ValueType, StateType>::setTerminalExpression(storm::expressions::Expression const& terminalExpression) { + this->terminalExpression = terminalExpression; + } + + template<typename ValueType, typename StateType> + bool PrismNextStateGenerator<ValueType, StateType>::isDeterministicModel() const { + return program.isDeterministicModel(); + } + template<typename ValueType, typename StateType> std::vector<StateType> PrismNextStateGenerator<ValueType, StateType>::getInitialStates(StateToIdCallback const& stateToIdCallback) { - // FIXME, TODO, whatever + // FIXME: This only works for models with exactly one initial state. We should make this more general. + CompressedState initialState(variableInformation.getTotalBitOffset()); + + // We need to initialize the values of the variables to their initial value. + for (auto const& booleanVariable : variableInformation.booleanVariables) { + initialState.set(booleanVariable.bitOffset, booleanVariable.initialValue); + } + for (auto const& integerVariable : variableInformation.integerVariables) { + initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast<uint_fast64_t>(integerVariable.initialValue - integerVariable.lowerBound)); + } + + // Register initial state and return it. + StateType id = stateToIdCallback(initialState); + return {id}; } template<typename ValueType, typename StateType> StateBehavior<ValueType, StateType> PrismNextStateGenerator<ValueType, StateType>::expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) { - // Start by unpacking the state into the evaluator so we can quickly evaluate expressions later. - unpackStateIntoEvaluator(state); - + // Since almost all subsequent operations are based on the evaluator, we load the state into it now. + unpackStateIntoEvaluator(state, variableInformation, evaluator); + // Prepare the result, in case we return early. StateBehavior<ValueType, StateType> result; @@ -45,6 +68,11 @@ namespace storm { result.addStateReward(stateReward); } + // If a terminal expression was set and we must not expand this state, return now. + if (terminalExpression && evaluator.asBool(terminalExpression.get())) { + return result; + } + // Get all choices for the state. std::vector<Choice<ValueType>> allChoices = getUnlabeledChoices(state, stateToIdCallback); std::vector<Choice<ValueType>> allLabeledChoices = getLabeledChoices(state, stateToIdCallback); @@ -112,21 +140,10 @@ namespace storm { result.addChoice(std::move(choice)); } + result.setExpanded(); return result; } - - - template<typename ValueType, typename StateType> - void PrismNextStateGenerator<ValueType, StateType>::unpackStateIntoEvaluator(storm::storage::BitVector const& state) { - for (auto const& booleanVariable : variableInformation.booleanVariables) { - evaluator.setBooleanValue(booleanVariable.variable, state.get(booleanVariable.bitOffset)); - } - for (auto const& integerVariable : variableInformation.integerVariables) { - evaluator.setIntegerValue(integerVariable.variable, state.getAsInt(integerVariable.bitOffset, integerVariable.bitWidth) + integerVariable.lowerBound); - } - } - template<typename ValueType, typename StateType> CompressedState PrismNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::prism::Update const& update) { CompressedState newState(state); diff --git a/src/generator/PrismNextStateGenerator.h b/src/generator/PrismNextStateGenerator.h index 282a2f25f..6e400e0eb 100644 --- a/src/generator/PrismNextStateGenerator.h +++ b/src/generator/PrismNextStateGenerator.h @@ -22,17 +22,16 @@ namespace storm { */ void addRewardModel(storm::prism::RewardModel const& rewardModel); - virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) override; - virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) override; - - private: /*! - * Unpacks the compressed state into the evaluator. - * - * @param state The state to unpack. + * Sets an expression such that if it evaluates to true in a state, prevents the exploration. */ - void unpackStateIntoEvaluator(CompressedState const& state); + void setTerminalExpression(storm::expressions::Expression const& terminalExpression); + virtual bool isDeterministicModel() const override; + virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) override; + virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) override; + + private: /*! * Applies an update to the state currently loaded into the evaluator and applies the resulting values to * the given compressed state. @@ -87,6 +86,9 @@ namespace storm { // A flag that stores whether or not to build the choice labeling. bool buildChoiceLabeling; + + // An optional expression that governs which states must not be explored. + boost::optional<storm::expressions::Expression> terminalExpression; // Information about how the variables are packed VariableInformation const& variableInformation; diff --git a/src/generator/StateBehavior.cpp b/src/generator/StateBehavior.cpp index 5868a1e40..bd5d489b7 100644 --- a/src/generator/StateBehavior.cpp +++ b/src/generator/StateBehavior.cpp @@ -3,6 +3,11 @@ namespace storm { namespace generator { + template<typename ValueType, typename StateType> + StateBehavior<ValueType, StateType>::StateBehavior() : expanded(false) { + // Intentionally left empty. + } + template<typename ValueType, typename StateType> void StateBehavior<ValueType, StateType>::addChoice(Choice<ValueType, StateType>&& choice) { choices.push_back(std::move(choice)); @@ -13,5 +18,35 @@ namespace storm { stateRewards.push_back(stateReward); } + template<typename ValueType, typename StateType> + bool StateBehavior<ValueType, StateType>::setExpanded(bool newValue) { + this->expanded = newValue; + } + + template<typename ValueType, typename StateType> + bool StateBehavior<ValueType, StateType>::wasExpanded() const { + return expanded; + } + + template<typename ValueType, typename StateType> + bool StateBehavior<ValueType, StateType>::empty() const { + return choices.empty(); + } + + template<typename ValueType, typename StateType> + typename std::vector<Choice<ValueType, StateType>>::const_iterator StateBehavior<ValueType, StateType>::begin() const { + return choices.begin(); + } + + template<typename ValueType, typename StateType> + typename std::vector<Choice<ValueType, StateType>>::const_iterator StateBehavior<ValueType, StateType>::end() const { + return choices.end(); + } + + template<typename ValueType, typename StateType> + std::vector<ValueType> const& StateBehavior<ValueType, StateType>::getStateRewards() const { + return stateRewards; + } + } } \ No newline at end of file diff --git a/src/generator/StateBehavior.h b/src/generator/StateBehavior.h index b4feecb34..9cbd26617 100644 --- a/src/generator/StateBehavior.h +++ b/src/generator/StateBehavior.h @@ -11,6 +11,11 @@ namespace storm { template<typename ValueType, typename StateType = uint32_t> class StateBehavior { public: + /*! + * Creates an empty behavior, i.e. the state was not yet expanded. + */ + StateBehavior(); + /*! * Adds the given choice to the behavior of the state. */ @@ -21,12 +26,45 @@ namespace storm { */ void addStateReward(ValueType const& stateReward); + /*! + * Sets whether the state was expanded. + */ + bool setExpanded(bool newValue = true); + + /*! + * Retrieves whether the state was expanded. + */ + bool wasExpanded() const; + + /*! + * Retrieves whether the behavior is empty in the sense that there are no available choices. + */ + bool empty() const; + + /*! + * Retrieves an iterator to the choices available in the behavior. + */ + typename std::vector<Choice<ValueType, StateType>>::const_iterator begin() const; + + /*! + * Retrieves an iterator past the choices available in the behavior. + */ + typename std::vector<Choice<ValueType, StateType>>::const_iterator end() const; + + /*! + * Retrieves the list of state rewards under selected reward models. + */ + std::vector<ValueType> const& getStateRewards() const; + private: // The choices available in the state. std::vector<Choice<ValueType, StateType>> choices; // The state rewards (under the different, selected reward models) of the state. std::vector<ValueType> stateRewards; + + // A flag indicating whether the state was actually expanded. + bool expanded; }; } diff --git a/src/generator/VariableInformation.h b/src/generator/VariableInformation.h index a06156336..c77d8f965 100644 --- a/src/generator/VariableInformation.h +++ b/src/generator/VariableInformation.h @@ -1,5 +1,5 @@ -#ifndef STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ -#define STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ +#ifndef STORM_GENERATOR_VARIABLEINFORMATION_H_ +#define STORM_GENERATOR_VARIABLEINFORMATION_H_ #include <vector> #include <boost/container/flat_map.hpp> @@ -71,4 +71,4 @@ namespace storm { } } -#endif /* STORM_GENERATOR_PRISM_VARIABLEINFORMATION_H_ */ \ No newline at end of file +#endif /* STORM_GENERATOR_VARIABLEINFORMATION_H_ */ \ No newline at end of file From e9b4f069728b23b73017bdd1119f9d7063b5dd53 Mon Sep 17 00:00:00 2001 From: Mavo <matthias.volk@rwth-aachen.de> Date: Fri, 26 Feb 2016 13:05:16 +0100 Subject: [PATCH 06/33] Better assertions in BitVector Former-commit-id: 7ee6b34ba5bced25fca9e1702e32a451e69f7d30 --- src/storage/BitVector.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/storage/BitVector.cpp b/src/storage/BitVector.cpp index cd5f46009..ddfcb9de9 100644 --- a/src/storage/BitVector.cpp +++ b/src/storage/BitVector.cpp @@ -412,6 +412,7 @@ namespace storm { } uint_fast64_t BitVector::getAsInt(uint_fast64_t bitIndex, uint_fast64_t numberOfBits) const { + STORM_LOG_ASSERT(numberOfBits <= 64, "Number of bits must be <= 64."); uint64_t bucket = bitIndex >> 6; uint64_t bitIndexInBucket = bitIndex & mod64mask; @@ -451,7 +452,8 @@ namespace storm { } void BitVector::setFromInt(uint_fast64_t bitIndex, uint_fast64_t numberOfBits, uint64_t value) { - STORM_LOG_ASSERT((value >> numberOfBits) == 0, "Integer value too large to fit in the given number of bits."); + STORM_LOG_ASSERT(numberOfBits <= 64, "Number of bits must be <= 64."); + STORM_LOG_ASSERT(numberOfBits == 64 || (value >> numberOfBits) == 0, "Integer value too large to fit in the given number of bits."); uint64_t bucket = bitIndex >> 6; uint64_t bitIndexInBucket = bitIndex & mod64mask; @@ -692,4 +694,4 @@ namespace std { std::size_t hash<storm::storage::BitVector>::operator()(storm::storage::BitVector const& bv) const { return boost::hash_range(bv.bucketVector.begin(), bv.bucketVector.end()); } -} \ No newline at end of file +} From fad28df7d626159be5348c9b4466e5697647e66e Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 26 Feb 2016 17:34:38 +0100 Subject: [PATCH 07/33] first working version of next-state generator for PRISM models Former-commit-id: 548a725e254bcbb924de20f37f24c93fcd916c9b --- src/builder/ExplicitPrismModelBuilder.cpp | 17 +++-- src/builder/ExplicitPrismModelBuilder.h | 2 +- src/generator/Choice.cpp | 31 +++------- src/generator/Choice.h | 23 ++----- src/generator/CompressedState.cpp | 5 +- src/generator/CompressedState.h | 2 +- src/generator/PrismNextStateGenerator.cpp | 62 ++++++++++--------- src/generator/PrismNextStateGenerator.h | 2 + src/generator/StateBehavior.cpp | 7 ++- src/generator/StateBehavior.h | 2 +- src/generator/VariableInformation.cpp | 8 ++- src/generator/VariableInformation.h | 3 +- src/storage/BitVector.cpp | 41 +++++++----- src/storage/BitVector.h | 2 +- src/storage/BitVectorHashMap.cpp | 2 +- src/storage/BitVectorHashMap.h | 2 +- src/storage/Distribution.cpp | 10 +++ src/storage/Distribution.h | 26 ++++++-- src/storage/prism/Program.cpp | 4 ++ .../builder/ExplicitPrismModelBuilderTest.cpp | 32 +++++----- .../GmmxxCtmcCslModelCheckerTest.cpp | 8 +-- .../GmmxxDtmcPrctlModelCheckerTest.cpp | 2 +- .../GmmxxMdpPrctlModelCheckerTest.cpp | 2 +- .../NativeCtmcCslModelCheckerTest.cpp | 8 +-- .../MilpPermissiveSchedulerTest.cpp | 2 +- .../SmtPermissiveSchedulerTest.cpp | 2 +- .../storage/BitVectorHashMapTest.cpp | 18 +++++- test/functional/storage/BitVectorTest.cpp | 18 ------ ...sticModelBisimulationDecompositionTest.cpp | 2 +- test/functional/utility/GraphTest.cpp | 8 +-- 30 files changed, 195 insertions(+), 158 deletions(-) diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp index 232d7f263..c0188de50 100644 --- a/src/builder/ExplicitPrismModelBuilder.cpp +++ b/src/builder/ExplicitPrismModelBuilder.cpp @@ -175,7 +175,7 @@ namespace storm { } template <typename ValueType, typename RewardModelType, typename StateType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ExplicitPrismModelBuilder(storm::prism::Program const& program, Options const& options) : program(program), options(options), variableInformation(program), internalStateInformation(variableInformation.getTotalBitOffset()) { + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ExplicitPrismModelBuilder(storm::prism::Program const& program, Options const& options) : program(program), options(options) { // Start by defining the undefined constants in the model. if (options.constantDefinitions) { this->program = program.defineUndefinedConstants(options.constantDefinitions.get()); @@ -226,6 +226,12 @@ namespace storm { // Now that the program is fixed, we we need to substitute all constants with their concrete value. this->program = program.substituteConstants(); + + // Create the variable information for the transformed program. + this->variableInformation = VariableInformation(this->program); + + // Create the internal state storage. + this->internalStateInformation = InternalStateInformation(variableInformation.getTotalBitOffset(true)); } template <typename ValueType, typename RewardModelType, typename StateType> @@ -331,7 +337,7 @@ namespace storm { std::function<StateType (CompressedState const&)> stateToIdCallback = std::bind(&ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex, this, std::placeholders::_1); // Let the generator create all initial states. - generator.getInitialStates(stateToIdCallback); + this->internalStateInformation.initialStateIndices = generator.getInitialStates(stateToIdCallback); // Now explore the current state until there is no more reachable state. uint_fast64_t currentRow = 0; @@ -403,13 +409,13 @@ namespace storm { } // Add the probabilistic behavior to the matrix. - for (auto const& stateProbabilityPair : behavior) { + for (auto const& stateProbabilityPair : choice) { transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second); } // Add the rewards to the reward models. auto builderIt = rewardModelBuilders.begin(); - auto choiceRewardIt = behavior.getChoiceRewards().begin(); + auto choiceRewardIt = choice.getChoiceRewards().begin(); for (auto const& rewardModel : selectedRewardModels) { if (rewardModel.get().hasStateActionRewards()) { builderIt->stateActionRewardVector.push_back(*choiceRewardIt); @@ -437,7 +443,6 @@ namespace storm { // Determine whether we have to combine different choices to one or whether this model can have more than // one choice per state. bool deterministicModel = program.isDeterministicModel(); - bool discreteTimeModel = program.isDiscreteTimeModel(); // Prepare the transition matrix builder and the reward model builders. storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0); @@ -477,7 +482,7 @@ namespace storm { STORM_LOG_TRACE("Making the states satisfying " << terminalExpression.get() << " terminal."); } - modelComponents.choiceLabeling = buildMatrices(program, variableInformation, selectedRewardModels, internalStateInformation, options.buildCommandLabels, deterministicModel, discreteTimeModel, transitionMatrixBuilder, rewardModelBuilders, terminalExpression); + modelComponents.choiceLabeling = buildMatrices(selectedRewardModels, transitionMatrixBuilder, rewardModelBuilders, terminalExpression); modelComponents.transitionMatrix = transitionMatrixBuilder.build(); // Now finalize all reward models. diff --git a/src/builder/ExplicitPrismModelBuilder.h b/src/builder/ExplicitPrismModelBuilder.h index 54fe9cf30..a5e09bfae 100644 --- a/src/builder/ExplicitPrismModelBuilder.h +++ b/src/builder/ExplicitPrismModelBuilder.h @@ -45,7 +45,7 @@ namespace storm { public: // A structure holding information about the reachable state space while building it. struct InternalStateInformation { - InternalStateInformation(uint64_t bitsPerState); + InternalStateInformation(uint64_t bitsPerState = 64); // This member stores all the states and maps them to their unique indices. storm::storage::BitVectorHashMap<StateType> stateStorage; diff --git a/src/generator/Choice.cpp b/src/generator/Choice.cpp index f80831ca0..9202f2c5e 100644 --- a/src/generator/Choice.cpp +++ b/src/generator/Choice.cpp @@ -1,5 +1,7 @@ #include "src/generator/Choice.h" +#include "src/adapters/CarlAdapter.h" + #include "src/utility/constants.h" namespace storm { @@ -61,30 +63,10 @@ namespace storm { return totalMass; } - template<typename ValueType, typename StateType> - ValueType& Choice<ValueType, StateType>::getOrAddEntry(StateType const& state) { - auto stateProbabilityPair = distribution.find(state); - - if (stateProbabilityPair == distribution.end()) { - distribution[state] = ValueType(); - } - return distribution.at(state); - } - - template<typename ValueType, typename StateType> - ValueType const& Choice<ValueType, StateType>::getOrAddEntry(StateType const& state) const { - auto stateProbabilityPair = distribution.find(state); - - if (stateProbabilityPair == distribution.end()) { - distribution[state] = ValueType(); - } - return distribution.at(state); - } - template<typename ValueType, typename StateType> void Choice<ValueType, StateType>::addProbability(StateType const& state, ValueType const& value) { totalMass += value; - distribution[state] += value; + distribution.addProbability(state, value); } template<typename ValueType, typename StateType> @@ -97,6 +79,11 @@ namespace storm { return choiceRewards; } + template<typename ValueType, typename StateType> + bool Choice<ValueType, StateType>::isMarkovian() const { + return markovian; + } + template<typename ValueType, typename StateType> std::size_t Choice<ValueType, StateType>::size() const { return distribution.size(); @@ -112,5 +99,7 @@ namespace storm { return out; } + template class Choice<double>; + template class Choice<storm::RationalFunction>; } } \ No newline at end of file diff --git a/src/generator/Choice.h b/src/generator/Choice.h index 95810bfb2..76b6c8d16 100644 --- a/src/generator/Choice.h +++ b/src/generator/Choice.h @@ -96,24 +96,6 @@ namespace storm { */ ValueType getTotalMass() const; - /*! - * Retrieves the entry in the choice that is associated with the given state and creates one if none exists, - * yet. - * - * @param state The state for which to add the entry. - * @return A reference to the entry that is associated with the given state. - */ - ValueType& getOrAddEntry(StateType const& state); - - /*! - * Retrieves the entry in the choice that is associated with the given state and creates one if none exists, - * yet. - * - * @param state The state for which to add the entry. - * @return A reference to the entry that is associated with the given state. - */ - ValueType const& getOrAddEntry(StateType const& state) const; - /*! * Adds the given probability value to the given state in the underlying distribution. */ @@ -129,6 +111,11 @@ namespace storm { */ std::vector<ValueType> const& getChoiceRewards() const; + /*! + * Retrieves whether the choice is Markovian. + */ + bool isMarkovian() const; + /*! * Retrieves the size of the distribution associated with this choice. */ diff --git a/src/generator/CompressedState.cpp b/src/generator/CompressedState.cpp index 1f71d2407..c63504ebb 100644 --- a/src/generator/CompressedState.cpp +++ b/src/generator/CompressedState.cpp @@ -7,7 +7,7 @@ namespace storm { namespace generator { template<typename ValueType> - static void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator) { + void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator) { for (auto const& booleanVariable : variableInformation.booleanVariables) { evaluator.setBooleanValue(booleanVariable.variable, state.get(booleanVariable.bitOffset)); } @@ -17,6 +17,7 @@ namespace storm { } - + template void unpackStateIntoEvaluator<double>(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<double>& evaluator); + template void unpackStateIntoEvaluator<storm::RationalFunction>(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<storm::RationalFunction>& evaluator); } } \ No newline at end of file diff --git a/src/generator/CompressedState.h b/src/generator/CompressedState.h index 512db591f..52f0b4a62 100644 --- a/src/generator/CompressedState.h +++ b/src/generator/CompressedState.h @@ -22,7 +22,7 @@ namespace storm { * @param evaluator The evaluator into which to load the state. */ template<typename ValueType> - static void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator); + void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator); } } diff --git a/src/generator/PrismNextStateGenerator.cpp b/src/generator/PrismNextStateGenerator.cpp index f8243998f..ad3ce3080 100644 --- a/src/generator/PrismNextStateGenerator.cpp +++ b/src/generator/PrismNextStateGenerator.cpp @@ -8,7 +8,7 @@ namespace storm { namespace generator { template<typename ValueType, typename StateType> - PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation, bool buildChoiceLabeling) : program(program), selectedRewardModels(), buildChoiceLabeling(buildChoiceLabeling), variableInformation(variableInformation), evaluator(), comparator() { + PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation, bool buildChoiceLabeling) : program(program), selectedRewardModels(), buildChoiceLabeling(buildChoiceLabeling), variableInformation(variableInformation), evaluator(program.getManager()), comparator() { // Intentionally left empty. } @@ -57,15 +57,15 @@ namespace storm { // First, construct the state rewards, as we may return early if there are no choices later and we already // need the state rewards then. for (auto const& rewardModel : selectedRewardModels) { - ValueType stateReward = storm::utility::zero<ValueType>(); - if (rewardModel->hasStateRewards()) { - for (auto const& stateReward : rewardModel->getStateRewards()) { + ValueType stateRewardValue = storm::utility::zero<ValueType>(); + if (rewardModel.get().hasStateRewards()) { + for (auto const& stateReward : rewardModel.get().getStateRewards()) { if (evaluator.asBool(stateReward.getStatePredicateExpression())) { - stateReward += ValueType(evaluator.asRational(stateReward.getRewardValueExpression())); + stateRewardValue += ValueType(evaluator.asRational(stateReward.getRewardValueExpression())); } } } - result.addStateReward(stateReward); + result.addStateReward(stateRewardValue); } // If a terminal expression was set and we must not expand this state, return now. @@ -94,21 +94,22 @@ namespace storm { // For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs // this is equal to the number of choices, which is why we initialize it like this here. - ValueType totalExitRate = static_cast<ValueType>(totalNumberOfChoices); + ValueType totalExitRate = program.isDiscreteTimeModel() ? static_cast<ValueType>(totalNumberOfChoices) : storm::utility::zero<ValueType>(); // Iterate over all choices and combine the probabilities/rates into one choice. for (auto const& choice : allChoices) { for (auto const& stateProbabilityPair : choice) { if (program.isDiscreteTimeModel()) { - globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second / totalNumberOfChoices; - if (hasStateActionRewards) { - totalExitRate += choice.getTotalMass(); - } + globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second / totalNumberOfChoices); } else { - globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second; + globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second); } } + if (hasStateActionRewards && !program.isDiscreteTimeModel()) { + totalExitRate += choice.getTotalMass(); + } + if (buildChoiceLabeling) { globalChoice.addChoiceLabels(choice.getChoiceLabels()); } @@ -116,18 +117,18 @@ namespace storm { // Now construct the state-action reward for all selected reward models. for (auto const& rewardModel : selectedRewardModels) { - ValueType stateActionReward = storm::utility::zero<ValueType>(); - if (rewardModel->hasStateActionRewards()) { - for (auto const& stateActionReward : rewardModel->getStateActionRewards()) { + ValueType stateActionRewardValue = storm::utility::zero<ValueType>(); + if (rewardModel.get().hasStateActionRewards()) { + for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) { for (auto const& choice : allChoices) { if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) { - stateActionReward += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) / totalExitRate; + stateActionRewardValue += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass() / totalExitRate; } } } } - globalChoice.addChoiceReward(stateActionReward); + globalChoice.addChoiceReward(stateActionRewardValue); } // Move the newly fused choice in place. @@ -266,15 +267,15 @@ namespace storm { // Create the state-action reward for the newly created choice. for (auto const& rewardModel : selectedRewardModels) { - ValueType stateActionReward = storm::utility::zero<ValueType>(); - if (rewardModel->hasStateActionRewards()) { - for (auto const& stateActionReward : rewardModel->getStateActionRewards()) { + ValueType stateActionRewardValue = storm::utility::zero<ValueType>(); + if (rewardModel.get().hasStateActionRewards()) { + for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) { if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) { - stateActionReward += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass(); + stateActionRewardValue += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass(); } } } - choice.addChoiceReward(stateActionReward); + choice.addChoiceReward(stateActionRewardValue); } // Check that the resulting distribution is in fact a distribution. @@ -290,7 +291,7 @@ namespace storm { std::vector<Choice<ValueType>> result; for (uint_fast64_t actionIndex : program.getSynchronizingActionIndices()) { - boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> optionalActiveCommandLists = getActiveCommandsByActionIndex(program, evaluator, actionIndex); + boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> optionalActiveCommandLists = getActiveCommandsByActionIndex(actionIndex); // Only process this action label, if there is at least one feasible solution. if (optionalActiveCommandLists) { @@ -317,7 +318,7 @@ namespace storm { for (auto const& stateProbabilityPair : *currentTargetStates) { // Compute the new state under the current update and add it to the set of new target states. - CompressedState newTargetState = applyUpdate(stateProbabilityPair.first, state, update); + CompressedState newTargetState = applyUpdate(stateProbabilityPair.first, update); newTargetStates->emplace(newTargetState, stateProbabilityPair.second * evaluator.asRational(update.getLikelihoodExpression())); } } @@ -359,15 +360,15 @@ namespace storm { // Create the state-action reward for the newly created choice. for (auto const& rewardModel : selectedRewardModels) { - ValueType stateActionReward = storm::utility::zero<ValueType>(); - if (rewardModel->hasStateActionRewards()) { - for (auto const& stateActionReward : rewardModel->getStateActionRewards()) { + ValueType stateActionRewardValue = storm::utility::zero<ValueType>(); + if (rewardModel.get().hasStateActionRewards()) { + for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) { if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) { - stateActionReward += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass(); + stateActionRewardValue += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass(); } } } - choice.addChoiceReward(stateActionReward); + choice.addChoiceReward(stateActionRewardValue); } // Dispose of the temporary maps. @@ -393,5 +394,8 @@ namespace storm { return result; } + + template class PrismNextStateGenerator<double>; + template class PrismNextStateGenerator<storm::RationalFunction>; } } \ No newline at end of file diff --git a/src/generator/PrismNextStateGenerator.h b/src/generator/PrismNextStateGenerator.h index 6e400e0eb..e9c63502e 100644 --- a/src/generator/PrismNextStateGenerator.h +++ b/src/generator/PrismNextStateGenerator.h @@ -7,6 +7,8 @@ #include "src/storage/prism/Program.h" #include "src/storage/expressions/ExpressionEvaluator.h" +#include "src/utility/ConstantsComparator.h" + namespace storm { namespace generator { diff --git a/src/generator/StateBehavior.cpp b/src/generator/StateBehavior.cpp index bd5d489b7..e14417779 100644 --- a/src/generator/StateBehavior.cpp +++ b/src/generator/StateBehavior.cpp @@ -1,5 +1,7 @@ #include "src/generator/StateBehavior.h" +#include "src/adapters/CarlAdapter.h" + namespace storm { namespace generator { @@ -19,7 +21,7 @@ namespace storm { } template<typename ValueType, typename StateType> - bool StateBehavior<ValueType, StateType>::setExpanded(bool newValue) { + void StateBehavior<ValueType, StateType>::setExpanded(bool newValue) { this->expanded = newValue; } @@ -47,6 +49,9 @@ namespace storm { std::vector<ValueType> const& StateBehavior<ValueType, StateType>::getStateRewards() const { return stateRewards; } + + template class StateBehavior<double>; + template class StateBehavior<storm::RationalFunction>; } } \ No newline at end of file diff --git a/src/generator/StateBehavior.h b/src/generator/StateBehavior.h index 9cbd26617..393c3280c 100644 --- a/src/generator/StateBehavior.h +++ b/src/generator/StateBehavior.h @@ -29,7 +29,7 @@ namespace storm { /*! * Sets whether the state was expanded. */ - bool setExpanded(bool newValue = true); + void setExpanded(bool newValue = true); /*! * Retrieves whether the state was expanded. diff --git a/src/generator/VariableInformation.cpp b/src/generator/VariableInformation.cpp index bb20c5225..a5be93a6e 100644 --- a/src/generator/VariableInformation.cpp +++ b/src/generator/VariableInformation.cpp @@ -45,8 +45,12 @@ namespace storm { } } - uint_fast64_t VariableInformation::getTotalBitOffset() const { - return totalBitOffset; + uint_fast64_t VariableInformation::getTotalBitOffset(bool roundTo64Bit) const { + uint_fast64_t result = totalBitOffset; + if (roundTo64Bit) { + result = ((result >> 6) + 1) << 6; + } + return result; } uint_fast64_t VariableInformation::getBitOffset(storm::expressions::Variable const& variable) const { diff --git a/src/generator/VariableInformation.h b/src/generator/VariableInformation.h index c77d8f965..8c2841dfd 100644 --- a/src/generator/VariableInformation.h +++ b/src/generator/VariableInformation.h @@ -49,8 +49,9 @@ namespace storm { // A structure storing information about the used variables of the program. struct VariableInformation { + VariableInformation() = default; VariableInformation(storm::prism::Program const& program); - uint_fast64_t getTotalBitOffset() const; + uint_fast64_t getTotalBitOffset(bool roundTo64Bit = false) const; // Provide methods to access the bit offset and width of variables in the compressed state. uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const; diff --git a/src/storage/BitVector.cpp b/src/storage/BitVector.cpp index 38b94d852..3e25e488d 100644 --- a/src/storage/BitVector.cpp +++ b/src/storage/BitVector.cpp @@ -64,7 +64,7 @@ namespace storm { // Intentionally left empty. } - BitVector::BitVector(uint_fast64_t length, bool init) : bitCount(length) { + BitVector::BitVector(uint_fast64_t length, bool init) : bitCount(length), buckets(nullptr) { // Compute the correct number of buckets needed to store the given number of bits. uint_fast64_t bucketCount = length >> 6; if ((length & mod64mask) != 0) { @@ -96,12 +96,12 @@ namespace storm { // Intentionally left empty. } - BitVector::BitVector(uint_fast64_t bucketCount, uint_fast64_t bitCount) : bitCount(bitCount) { + BitVector::BitVector(uint_fast64_t bucketCount, uint_fast64_t bitCount) : bitCount(bitCount), buckets(nullptr) { STORM_LOG_ASSERT((bucketCount << 6) == bitCount, "Bit count does not match number of buckets."); buckets = new uint64_t[bucketCount](); } - BitVector::BitVector(BitVector const& other) : bitCount(other.bitCount) { + BitVector::BitVector(BitVector const& other) : bitCount(other.bitCount), buckets(nullptr) { buckets = new uint64_t[other.bucketCount()]; std::copy_n(other.buckets, other.bucketCount(), buckets); } @@ -136,6 +136,11 @@ namespace storm { } return false; } + + BitVector::BitVector(BitVector&& other) : bitCount(other.bitCount), buckets(other.buckets) { + other.bitCount = 0; + other.buckets = nullptr; + } BitVector& BitVector::operator=(BitVector&& other) { // Only perform the assignment if the source and target are not identical. @@ -202,11 +207,13 @@ namespace storm { std::copy_n(buckets, this->bucketCount(), newBuckets); if (init) { newBuckets[this->bucketCount() - 1] |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull); - std::fill_n(newBuckets, newBucketCount - this->bucketCount(), -1ull); + std::fill_n(newBuckets + this->bucketCount(), newBucketCount - this->bucketCount(), -1ull); } else { - std::fill_n(newBuckets, newBucketCount - this->bucketCount(), 0); + std::fill_n(newBuckets + this->bucketCount(), newBucketCount - this->bucketCount(), 0); + } + if (buckets != nullptr) { + delete buckets; } - delete buckets; buckets = newBuckets; bitCount = newLength; } else { @@ -228,7 +235,9 @@ namespace storm { if (newBucketCount < this->bucketCount()) { uint64_t* newBuckets = new uint64_t[newBucketCount]; std::copy_n(buckets, newBucketCount, newBuckets); - delete buckets; + if (buckets != nullptr) { + delete buckets; + } buckets = newBuckets; bitCount = newLength; } @@ -473,19 +482,19 @@ namespace storm { bool BitVector::empty() const { uint64_t* last = buckets + bucketCount(); - uint64_t* it = std::find(buckets, last, 0); - return it != last; + uint64_t* it = std::find_if(buckets, last, [] (uint64_t const& a) { return a != 0; }); + return it == last; } bool BitVector::full() const { // Check that all buckets except the last one have all bits set. uint64_t* last = buckets + bucketCount() - 1; - for (uint64_t const* it = buckets; it != last; ++it) { + for (uint64_t const* it = buckets; it < last; ++it) { if (*it != -1ull) { return false; } } - + // Now check whether the relevant bits are set in the last bucket. uint64_t mask = ~((1ull << (64 - (bitCount & mod64mask))) - 1ull); if ((*last & mask) != mask) { @@ -627,7 +636,11 @@ namespace storm { } size_t BitVector::bucketCount() const { - return bitCount >> 6; + size_t result = (bitCount >> 6); + if ((bitCount & mod64mask) != 0) { + ++result; + } + return result; } std::ostream& operator<<(std::ostream& out, BitVector const& bitvector) { @@ -670,7 +683,7 @@ namespace storm { namespace std { - std::size_t hash<storm::storage::BitVector>::operator()(storm::storage::BitVector const& bv) const { - return boost::hash_range(bv.bucketVector.begin(), bv.bucketVector.end()); + std::size_t hash<storm::storage::BitVector>::operator()(storm::storage::BitVector const& bitvector) const { + return boost::hash_range(bitvector.buckets, bitvector.buckets + bitvector.bucketCount()); } } \ No newline at end of file diff --git a/src/storage/BitVector.h b/src/storage/BitVector.h index a6ad89cc3..f15eef3ed 100644 --- a/src/storage/BitVector.h +++ b/src/storage/BitVector.h @@ -146,7 +146,7 @@ namespace storm { * * @param other The bit vector from which to move-construct. */ - BitVector(BitVector&& other) = default; + BitVector(BitVector&& other); /*! * Compares the given bit vector with the current one. diff --git a/src/storage/BitVectorHashMap.cpp b/src/storage/BitVectorHashMap.cpp index c184b764b..881fc016a 100644 --- a/src/storage/BitVectorHashMap.cpp +++ b/src/storage/BitVectorHashMap.cpp @@ -40,7 +40,7 @@ namespace storm { std::pair<storm::storage::BitVector, ValueType> BitVectorHashMap<ValueType, Hash1, Hash2>::BitVectorHashMapIterator::operator*() const { return map.getBucketAndValue(*indexIt); } - + template<class ValueType, class Hash1, class Hash2> BitVectorHashMap<ValueType, Hash1, Hash2>::BitVectorHashMap(uint64_t bucketSize, uint64_t initialSize, double loadFactor) : loadFactor(loadFactor), bucketSize(bucketSize), numberOfElements(0) { STORM_LOG_ASSERT(bucketSize % 64 == 0, "Bucket size must be a multiple of 64."); diff --git a/src/storage/BitVectorHashMap.h b/src/storage/BitVectorHashMap.h index 3b0c7aa70..c53928b09 100644 --- a/src/storage/BitVectorHashMap.h +++ b/src/storage/BitVectorHashMap.h @@ -55,7 +55,7 @@ namespace storm { * @param loadFactor The load factor that determines at which point the size of the underlying storage is * increased. */ - BitVectorHashMap(uint64_t bucketSize, uint64_t initialSize, double loadFactor = 0.75); + BitVectorHashMap(uint64_t bucketSize = 64, uint64_t initialSize = 1000, double loadFactor = 0.75); /*! * Searches for the given key in the map. If it is found, the mapped-to value is returned. Otherwise, the diff --git a/src/storage/Distribution.cpp b/src/storage/Distribution.cpp index 516227277..5843e964b 100644 --- a/src/storage/Distribution.cpp +++ b/src/storage/Distribution.cpp @@ -78,6 +78,11 @@ namespace storm { return this->distribution.begin(); } + template<typename ValueType, typename StateType> + typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::cbegin() const { + return this->begin(); + } + template<typename ValueType, typename StateType> typename Distribution<ValueType, StateType>::iterator Distribution<ValueType, StateType>::end() { return this->distribution.end(); @@ -87,6 +92,11 @@ namespace storm { typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::end() const { return this->distribution.end(); } + + template<typename ValueType, typename StateType> + typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::cend() const { + return this->end(); + } template<typename ValueType, typename StateType> void Distribution<ValueType, StateType>::scale(StateType const& state) { diff --git a/src/storage/Distribution.h b/src/storage/Distribution.h index 39e6eb6f9..ba61f0fbd 100644 --- a/src/storage/Distribution.h +++ b/src/storage/Distribution.h @@ -17,7 +17,7 @@ namespace storm { namespace storage { - template<typename ValueType, typename StateType=storm::storage::sparse::state_type> + template<typename ValueType, typename StateType = uint32_t> class Distribution { public: typedef boost::container::flat_map<StateType, ValueType> container_type; @@ -43,7 +43,7 @@ namespace storm { * @param other The distribution with which the current distribution is to be compared. * @return True iff the two distributions are equal. */ - bool equals(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>()) const; + bool equals(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>()) const; /*! * Assigns the given state the given probability under this distribution. @@ -73,7 +73,7 @@ namespace storm { * entry is removed. */ void shiftProbability(StateType const& fromState, StateType const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>()); - + /*! * Retrieves an iterator to the elements in this distribution. * @@ -88,6 +88,13 @@ namespace storm { */ const_iterator begin() const; + /*! + * Retrieves an iterator to the elements in this distribution. + * + * @return The iterator to the elements in this distribution. + */ + const_iterator cbegin() const; + /*! * Retrieves an iterator past the elements in this distribution. * @@ -102,6 +109,13 @@ namespace storm { */ const_iterator end() const; + /*! + * Retrieves an iterator past the elements in this distribution. + * + * @return The iterator past the elements in this distribution. + */ + const_iterator cend() const; + /*! * Scales the distribution by multiplying all the probabilities with 1/p where p is the probability of moving * to the given state and sets the probability of moving to the given state to zero. If the probability is @@ -116,15 +130,15 @@ namespace storm { */ std::size_t size() const; - bool less(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const; + bool less(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const; private: // A list of states and the probabilities that are assigned to them. container_type distribution; }; - template<typename ValueType> - std::ostream& operator<<(std::ostream& out, Distribution<ValueType> const& distribution); + template<typename ValueType, typename StateType = uint32_t> + std::ostream& operator<<(std::ostream& out, Distribution<ValueType, StateType> const& distribution); } } diff --git a/src/storage/prism/Program.cpp b/src/storage/prism/Program.cpp index 0f5aea4a8..999cf2f30 100644 --- a/src/storage/prism/Program.cpp +++ b/src/storage/prism/Program.cpp @@ -81,6 +81,10 @@ namespace storm { return modelType == ModelType::DTMC || modelType == ModelType::MDP; } + bool Program::isDeterministicModel() const { + return modelType == ModelType::DTMC || modelType == ModelType::CTMC; + } + bool Program::hasUndefinedConstants() const { for (auto const& constant : this->getConstants()) { if (!constant.isDefined()) { diff --git a/test/functional/builder/ExplicitPrismModelBuilderTest.cpp b/test/functional/builder/ExplicitPrismModelBuilderTest.cpp index 080b6c16f..c2151c74c 100644 --- a/test/functional/builder/ExplicitPrismModelBuilderTest.cpp +++ b/test/functional/builder/ExplicitPrismModelBuilderTest.cpp @@ -10,27 +10,27 @@ TEST(ExplicitPrismModelBuilderTest, Dtmc) { storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/die.pm"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(13ul, model->getNumberOfStates()); EXPECT_EQ(20ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/brp-16-2.pm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(677ul, model->getNumberOfStates()); EXPECT_EQ(867ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/crowds-5-5.pm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(8607ul, model->getNumberOfStates()); EXPECT_EQ(15113ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader-3-5.pm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(273ul, model->getNumberOfStates()); EXPECT_EQ(397ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/nand-5-2.pm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(1728ul, model->getNumberOfStates()); EXPECT_EQ(2505ul, model->getNumberOfTransitions()); } @@ -41,27 +41,27 @@ TEST(ExplicitPrismModelBuilderTest, Ctmc) { storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(276ul, model->getNumberOfStates()); EXPECT_EQ(1120ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(3478ul, model->getNumberOfStates()); EXPECT_EQ(14639ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(12ul, model->getNumberOfStates()); EXPECT_EQ(22ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/fms2.sm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(810ul, model->getNumberOfStates()); EXPECT_EQ(3699ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(66ul, model->getNumberOfStates()); EXPECT_EQ(189ul, model->getNumberOfTransitions()); } @@ -69,32 +69,32 @@ TEST(ExplicitPrismModelBuilderTest, Ctmc) { TEST(ExplicitPrismModelBuilderTest, Mdp) { storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/two_dice.nm"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(169ul, model->getNumberOfStates()); EXPECT_EQ(436ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader3.nm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(364ul, model->getNumberOfStates()); EXPECT_EQ(654ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(272ul, model->getNumberOfStates()); EXPECT_EQ(492ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/csma2-2.nm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(1038ul, model->getNumberOfStates()); EXPECT_EQ(1282ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/firewire3-0.5.nm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(4093ul, model->getNumberOfStates()); EXPECT_EQ(5585ul, model->getNumberOfTransitions()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/wlan0-2-2.nm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(37ul, model->getNumberOfStates()); EXPECT_EQ(59ul, model->getNumberOfTransitions()); } \ No newline at end of file diff --git a/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp index b36983962..dc9512a38 100644 --- a/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp @@ -34,7 +34,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Cluster) { #endif options.buildAllRewardModels = false; options.rewardModelsToBuild.insert("num_repairs"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate(); ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>(); uint_fast64_t initialState = *ctmc->getInitialStates().begin(); @@ -117,7 +117,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Embedded) { #endif options.buildAllRewardModels = false; options.rewardModelsToBuild.insert("up"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate(); ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>(); uint_fast64_t initialState = *ctmc->getInitialStates().begin(); @@ -179,7 +179,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Polling) { std::shared_ptr<const storm::logic::Formula> formula(nullptr); // Build the model. - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>(); uint_fast64_t initialState = *ctmc->getInitialStates().begin(); @@ -226,7 +226,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Tandem) { typename storm::builder::ExplicitPrismModelBuilder<double>::Options options; #endif options.rewardModelsToBuild.insert("customers"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate(); ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>(); uint_fast64_t initialState = *ctmc->getInitialStates().begin(); diff --git a/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp index 1e131c335..36a139b9c 100644 --- a/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp @@ -284,7 +284,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, LRA) { TEST(GmmxxDtmcPrctlModelCheckerTest, Conditional) { storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/modelchecker/test_conditional.pm"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); ASSERT_TRUE(model->getType() == storm::models::ModelType::Dtmc); ASSERT_EQ(4ul, model->getNumberOfStates()); ASSERT_EQ(5ul, model->getNumberOfTransitions()); diff --git a/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp index 725e1376d..93643fd52 100644 --- a/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp @@ -197,7 +197,7 @@ TEST(GmmxxMdpPrctlModelCheckerTest, SchedulerGeneration) { // A parser that we use for conveniently constructing the formulas. storm::parser::FormulaParser formulaParser; - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); EXPECT_EQ(4ul, model->getNumberOfStates()); EXPECT_EQ(11ul, model->getNumberOfTransitions()); diff --git a/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp b/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp index 72788de80..0a1d8ee4c 100644 --- a/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp +++ b/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp @@ -32,7 +32,7 @@ TEST(NativeCtmcCslModelCheckerTest, Cluster) { #endif options.buildAllRewardModels = false; options.rewardModelsToBuild.insert("num_repairs"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate(); ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>(); uint_fast64_t initialState = *ctmc->getInitialStates().begin(); @@ -108,7 +108,7 @@ TEST(NativeCtmcCslModelCheckerTest, Embedded) { #endif options.buildAllRewardModels = false; options.rewardModelsToBuild.insert("up"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate(); ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>(); uint_fast64_t initialState = *ctmc->getInitialStates().begin(); @@ -163,7 +163,7 @@ TEST(NativeCtmcCslModelCheckerTest, Polling) { std::shared_ptr<const storm::logic::Formula> formula(nullptr); // Build the model. - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>(); uint_fast64_t initialState = *ctmc->getInitialStates().begin(); @@ -204,7 +204,7 @@ TEST(NativeCtmcCslModelCheckerTest, Tandem) { #endif options.buildAllRewardModels = false; options.rewardModelsToBuild.insert("customers"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate(); ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>(); uint_fast64_t initialState = *ctmc->getInitialStates().begin(); diff --git a/test/functional/permissiveschedulers/MilpPermissiveSchedulerTest.cpp b/test/functional/permissiveschedulers/MilpPermissiveSchedulerTest.cpp index 75bea3570..657d36575 100644 --- a/test/functional/permissiveschedulers/MilpPermissiveSchedulerTest.cpp +++ b/test/functional/permissiveschedulers/MilpPermissiveSchedulerTest.cpp @@ -28,7 +28,7 @@ TEST(MilpPermissiveSchedulerTest, DieSelection) { options.addConstantDefinitionsFromString(program, ""); options.buildCommandLabels = true; - std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options)->as<storm::models::sparse::Mdp<double>>(); + std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate()->as<storm::models::sparse::Mdp<double>>(); boost::optional<storm::ps::SubMDPPermissiveScheduler<>> perms = storm::ps::computePermissiveSchedulerViaMILP<>(*mdp, formula02); EXPECT_NE(perms, boost::none); diff --git a/test/functional/permissiveschedulers/SmtPermissiveSchedulerTest.cpp b/test/functional/permissiveschedulers/SmtPermissiveSchedulerTest.cpp index 4d87796b8..2790cd86a 100644 --- a/test/functional/permissiveschedulers/SmtPermissiveSchedulerTest.cpp +++ b/test/functional/permissiveschedulers/SmtPermissiveSchedulerTest.cpp @@ -31,7 +31,7 @@ TEST(SmtPermissiveSchedulerTest, DieSelection) { options.addConstantDefinitionsFromString(program, ""); options.buildCommandLabels = true; - std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options)->as<storm::models::sparse::Mdp<double>>(); + std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate()->as<storm::models::sparse::Mdp<double>>(); // boost::optional<storm::ps::SubMDPPermissiveScheduler<>> perms = storm::ps::computePermissiveSchedulerViaSMT<>(*mdp, formula02); // EXPECT_NE(perms, boost::none); diff --git a/test/functional/storage/BitVectorHashMapTest.cpp b/test/functional/storage/BitVectorHashMapTest.cpp index 616941f21..1149433fd 100644 --- a/test/functional/storage/BitVectorHashMapTest.cpp +++ b/test/functional/storage/BitVectorHashMapTest.cpp @@ -19,25 +19,41 @@ TEST(BitVectorHashMapTest, FindOrAdd) { ASSERT_NO_THROW(map.findOrAdd(second, 2)); EXPECT_EQ(1ul, map.findOrAdd(first, 3)); - + EXPECT_EQ(2ul, map.findOrAdd(second, 3)); + storm::storage::BitVector third(64); third.set(10); third.set(63); ASSERT_NO_THROW(map.findOrAdd(third, 3)); + EXPECT_EQ(1ul, map.findOrAdd(first, 2)); + EXPECT_EQ(2ul, map.findOrAdd(second, 1)); + EXPECT_EQ(3ul, map.findOrAdd(third, 1)); + storm::storage::BitVector fourth(64); fourth.set(12); fourth.set(14); ASSERT_NO_THROW(map.findOrAdd(fourth, 4)); + EXPECT_EQ(1ul, map.findOrAdd(first, 2)); + EXPECT_EQ(2ul, map.findOrAdd(second, 1)); + EXPECT_EQ(3ul, map.findOrAdd(third, 1)); + EXPECT_EQ(4ul, map.findOrAdd(fourth, 1)); + storm::storage::BitVector fifth(64); fifth.set(44); fifth.set(55); ASSERT_NO_THROW(map.findOrAdd(fifth, 5)); + EXPECT_EQ(1ul, map.findOrAdd(first, 2)); + EXPECT_EQ(2ul, map.findOrAdd(second, 1)); + EXPECT_EQ(3ul, map.findOrAdd(third, 1)); + EXPECT_EQ(4ul, map.findOrAdd(fourth, 1)); + EXPECT_EQ(5ul, map.findOrAdd(fifth, 1)); + storm::storage::BitVector sixth(64); sixth.set(45); sixth.set(55); diff --git a/test/functional/storage/BitVectorTest.cpp b/test/functional/storage/BitVectorTest.cpp index db92724fe..7266f829b 100644 --- a/test/functional/storage/BitVectorTest.cpp +++ b/test/functional/storage/BitVectorTest.cpp @@ -321,24 +321,6 @@ TEST(BitVectorTest, OperatorModulo) { ASSERT_FALSE(moduloResult.get(i)); } } - - storm::storage::BitVector vector3(31); - - for (uint_fast64_t i = 0; i < 15; ++i) { - vector3.set(i, i % 2 == 0); - } - - -#ifndef NDEBUG -#ifdef WINDOWS - EXPECT_EXIT(vector1 % vector3, ::testing::ExitedWithCode(0), ".*"); -#else - EXPECT_DEATH_IF_SUPPORTED(vector1 % vector3, ""); -#endif -#else - std::cerr << "WARNING: Not testing OperatorModulo size check, as assertions are disabled in release mode." << std::endl; - SUCCEED(); -#endif } TEST(BitVectorTest, OperatorNot) { diff --git a/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp b/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp index 3754b03fd..fe0a199b7 100644 --- a/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp +++ b/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp @@ -14,7 +14,7 @@ TEST(NondeterministicModelBisimulationDecomposition, TwoDice) { storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/two_dice.nm"); // Build the die model without its reward model. - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); ASSERT_EQ(model->getType(), storm::models::ModelType::Mdp); std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = model->as<storm::models::sparse::Mdp<double>>(); diff --git a/test/functional/utility/GraphTest.cpp b/test/functional/utility/GraphTest.cpp index d209998d7..4c6bf0d50 100644 --- a/test/functional/utility/GraphTest.cpp +++ b/test/functional/utility/GraphTest.cpp @@ -181,7 +181,7 @@ TEST(GraphTest, SymbolicProb01MinMax_Sylvan) { TEST(GraphTest, ExplicitProb01) { storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/crowds-5-5.pm"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); ASSERT_TRUE(model->getType() == storm::models::ModelType::Dtmc); @@ -202,7 +202,7 @@ TEST(GraphTest, ExplicitProb01) { TEST(GraphTest, ExplicitProb01MinMax) { storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader3.nm"); - std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); ASSERT_TRUE(model->getType() == storm::models::ModelType::Mdp); @@ -217,7 +217,7 @@ TEST(GraphTest, ExplicitProb01MinMax) { EXPECT_EQ(364ul, statesWithProbability01.second.getNumberOfSetBits()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); ASSERT_TRUE(model->getType() == storm::models::ModelType::Mdp); @@ -238,7 +238,7 @@ TEST(GraphTest, ExplicitProb01MinMax) { EXPECT_EQ(35ul, statesWithProbability01.second.getNumberOfSetBits()); program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/csma2-2.nm"); - model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program); + model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); ASSERT_TRUE(model->getType() == storm::models::ModelType::Mdp); From fff7b2d5db96476d5afb4b21f000070547646005 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 26 Feb 2016 19:51:41 +0100 Subject: [PATCH 08/33] fixed an allocation issue, performance is now roughly the same as before but memory consumption is reduced Former-commit-id: ff4480497502ea159c87a8de216f469683ebf2ea --- src/builder/ExplicitPrismModelBuilder.cpp | 16 ++++++++-------- src/builder/ExplicitPrismModelBuilder.h | 6 +++++- src/utility/storm.h | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp index c0188de50..9a0408a3c 100644 --- a/src/builder/ExplicitPrismModelBuilder.cpp +++ b/src/builder/ExplicitPrismModelBuilder.cpp @@ -67,7 +67,12 @@ namespace storm { } template <typename ValueType, typename RewardModelType, typename StateType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::InternalStateInformation::InternalStateInformation(uint64_t bitsPerState) : stateStorage(bitsPerState, 10000000), bitsPerState(bitsPerState), numberOfStates() { + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::InternalStateInformation::InternalStateInformation() : stateStorage(64, 10), initialStateIndices(), bitsPerState(64), numberOfStates() { + // Intentionally left empty. + } + + template <typename ValueType, typename RewardModelType, typename StateType> + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::InternalStateInformation::InternalStateInformation(uint64_t bitsPerState) : stateStorage(bitsPerState, 10000000), initialStateIndices(), bitsPerState(bitsPerState), numberOfStates() { // Intentionally left empty. } @@ -349,7 +354,7 @@ namespace storm { StateType currentIndex = internalStateInformation.stateStorage.getValue(currentState); statesToExplore.pop_front(); - STORM_LOG_TRACE("Exploring state with id " << index << "."); + STORM_LOG_TRACE("Exploring state with id " << currentIndex << "."); storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(currentState, stateToIdCallback); @@ -423,7 +428,6 @@ namespace storm { ++choiceRewardIt; ++builderIt; } - ++currentRow; } } @@ -435,11 +439,7 @@ namespace storm { template <typename ValueType, typename RewardModelType, typename StateType> typename ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ModelComponents ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildModelComponents(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels) { ModelComponents modelComponents; - - // Create the structure for storing the reachable state space. - uint64_t bitsPerState = ((variableInformation.getTotalBitOffset() / 64) + 1) * 64; - InternalStateInformation internalStateInformation(bitsPerState); - + // Determine whether we have to combine different choices to one or whether this model can have more than // one choice per state. bool deterministicModel = program.isDeterministicModel(); diff --git a/src/builder/ExplicitPrismModelBuilder.h b/src/builder/ExplicitPrismModelBuilder.h index a5e09bfae..3e5614854 100644 --- a/src/builder/ExplicitPrismModelBuilder.h +++ b/src/builder/ExplicitPrismModelBuilder.h @@ -45,7 +45,11 @@ namespace storm { public: // A structure holding information about the reachable state space while building it. struct InternalStateInformation { - InternalStateInformation(uint64_t bitsPerState = 64); + // Builds an empty state information. + InternalStateInformation(); + + // Creates a state information structure for storing states of the given bit width. + InternalStateInformation(uint64_t bitsPerState); // This member stores all the states and maps them to their unique indices. storm::storage::BitVectorHashMap<StateType> stateStorage; diff --git a/src/utility/storm.h b/src/utility/storm.h index d4a042bc6..ef2e7ac7a 100644 --- a/src/utility/storm.h +++ b/src/utility/storm.h @@ -106,8 +106,8 @@ namespace storm { options.buildCommandLabels = true; } - storm::builder::ExplicitPrismModelBuilder<ValueType> builder; - result.model = builder.translateProgram(program, options); + storm::builder::ExplicitPrismModelBuilder<ValueType> builder(program, options); + result.model = builder.translate(); translatedProgram = builder.getTranslatedProgram(); } else if (settings.getEngine() == storm::settings::modules::GeneralSettings::Engine::Dd || settings.getEngine() == storm::settings::modules::GeneralSettings::Engine::Hybrid) { typename storm::builder::DdPrismModelBuilder<LibraryType>::Options options; From 0dfdfe7db80e499c74d4373b7b084bbd9be21b20 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Sat, 27 Feb 2016 16:25:19 +0100 Subject: [PATCH 09/33] using flat_map in model building instead of unordered_map Former-commit-id: ff895d2bcc95582afafdaae0760df92ea801693d --- src/generator/PrismNextStateGenerator.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/generator/PrismNextStateGenerator.cpp b/src/generator/PrismNextStateGenerator.cpp index ad3ce3080..fac3be0f5 100644 --- a/src/generator/PrismNextStateGenerator.cpp +++ b/src/generator/PrismNextStateGenerator.cpp @@ -1,5 +1,7 @@ #include "src/generator/PrismNextStateGenerator.h" +#include <boost/container/flat_map.hpp> + #include "src/utility/constants.h" #include "src/utility/macros.h" #include "src/exceptions/WrongFormatException.h" @@ -306,8 +308,9 @@ namespace storm { // As long as there is one feasible combination of commands, keep on expanding it. bool done = false; while (!done) { - std::unordered_map<CompressedState, ValueType>* currentTargetStates = new std::unordered_map<CompressedState, ValueType>(); - std::unordered_map<CompressedState, ValueType>* newTargetStates = new std::unordered_map<CompressedState, ValueType>(); + boost::container::flat_map<CompressedState, ValueType>* currentTargetStates = new boost::container::flat_map<CompressedState, ValueType>(); + boost::container::flat_map<CompressedState, ValueType>* newTargetStates = new boost::container::flat_map<CompressedState, ValueType>(); + currentTargetStates->emplace(state, storm::utility::one<ValueType>()); for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { @@ -327,7 +330,7 @@ namespace storm { if (i < iteratorList.size() - 1) { delete currentTargetStates; currentTargetStates = newTargetStates; - newTargetStates = new std::unordered_map<CompressedState, ValueType>(); + newTargetStates = new boost::container::flat_map<CompressedState, ValueType>(); } } From 55fd1b66c3c0a302fe4a44f28de218e6aedee7aa Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 29 Feb 2016 16:06:01 +0100 Subject: [PATCH 10/33] introducing exploration orders to explicit builder Former-commit-id: a56620eac2c37abbda99a16ff2dc880813e2b185 --- src/builder/ExplicitPrismModelBuilder.cpp | 65 +++++++++++++++- src/builder/ExplicitPrismModelBuilder.h | 22 ++++-- src/builder/ExplorationOrder.cpp | 22 ++++++ src/builder/ExplorationOrder.h | 17 +++++ src/settings/modules/GeneralSettings.cpp | 21 ++++++ src/settings/modules/GeneralSettings.h | 19 ++++- src/storage/BitVectorHashMap.cpp | 10 +++ src/storage/BitVectorHashMap.h | 8 ++ src/storage/SparseMatrix.cpp | 92 +++++++++++++++++++---- src/storage/SparseMatrix.h | 16 ++++ src/storage/prism/RewardModel.cpp | 2 +- src/utility/constants.cpp | 4 + 12 files changed, 273 insertions(+), 25 deletions(-) create mode 100644 src/builder/ExplorationOrder.cpp create mode 100644 src/builder/ExplorationOrder.h diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp index 9a0408a3c..1aeab458d 100644 --- a/src/builder/ExplicitPrismModelBuilder.cpp +++ b/src/builder/ExplicitPrismModelBuilder.cpp @@ -24,6 +24,7 @@ namespace storm { namespace builder { + /*! * A structure that is used to keep track of a reward model currently being built. */ @@ -82,17 +83,17 @@ namespace storm { } template <typename ValueType, typename RewardModelType, typename StateType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options() : buildCommandLabels(false), buildAllRewardModels(true), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(true), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() { + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options() : explorationOrder(storm::settings::generalSettings().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(true), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(true), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() { // Intentionally left empty. } template <typename ValueType, typename RewardModelType, typename StateType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(storm::logic::Formula const& formula) : buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(std::set<std::string>()), expressionLabels(std::vector<storm::expressions::Expression>()), terminalStates(), negatedTerminalStates() { + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(storm::logic::Formula const& formula) : explorationOrder(storm::settings::generalSettings().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(std::set<std::string>()), expressionLabels(std::vector<storm::expressions::Expression>()), terminalStates(), negatedTerminalStates() { this->preserveFormula(formula); } template <typename ValueType, typename RewardModelType, typename StateType> - ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(std::vector<std::shared_ptr<const storm::logic::Formula>> const& formulas) : buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() { + ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(std::vector<std::shared_ptr<const storm::logic::Formula>> const& formulas) : explorationOrder(storm::settings::generalSettings().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() { if (formulas.empty()) { this->buildAllRewardModels = true; this->buildAllLabels = true; @@ -253,6 +254,7 @@ namespace storm { template <typename ValueType, typename RewardModelType, typename StateType> std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::translate() { STORM_LOG_DEBUG("Building representation of program:" << std::endl << program << std::endl); + STORM_LOG_DEBUG("Exploration order is: " << options.explorationOrder); // Select the appropriate reward models (after the constants have been substituted). std::vector<std::reference_wrapper<storm::prism::RewardModel const>> selectedRewardModels; @@ -314,7 +316,16 @@ namespace storm { std::pair<uint32_t, std::size_t> actualIndexBucketPair = internalStateInformation.stateStorage.findOrAddAndGetBucket(state, newIndex); if (actualIndexBucketPair.first == newIndex) { - statesToExplore.push_back(state); + if (options.explorationOrder == ExplorationOrder::Dfs) { + statesToExplore.push_front(state); + + // Reserve one slot for the new state in the remapping. + stateRemapping.get().push_back(storm::utility::zero<StateType>()); + } else if (options.explorationOrder == ExplorationOrder::Bfs) { + statesToExplore.push_back(state); + } else { + STORM_LOG_ASSERT(false, "Invalid exploration order."); + } ++internalStateInformation.numberOfStates; } @@ -341,10 +352,18 @@ namespace storm { // Create a callback for the next-state generator to enable it to request the index of states. std::function<StateType (CompressedState const&)> stateToIdCallback = std::bind(&ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex, this, std::placeholders::_1); + // If the exploration order is something different from breadth-first, we need to keep track of the remapping + // from state ids to row groups. For this, we actually store the reversed mapping of row groups to state-ids + // and later reverse it. + if (options.explorationOrder != ExplorationOrder::Bfs) { + stateRemapping = std::vector<uint_fast64_t>(); + } + // Let the generator create all initial states. this->internalStateInformation.initialStateIndices = generator.getInitialStates(stateToIdCallback); // Now explore the current state until there is no more reachable state. + uint_fast64_t currentRowGroup = 0; uint_fast64_t currentRow = 0; // Perform a search through the model. @@ -354,6 +373,12 @@ namespace storm { StateType currentIndex = internalStateInformation.stateStorage.getValue(currentState); statesToExplore.pop_front(); + // If the exploration order differs from breadth-first, we remember that this row group was actually + // filled with the transitions of a different state. + if (options.explorationOrder != ExplorationOrder::Bfs) { + stateRemapping.get()[currentIndex] = currentRowGroup; + } + STORM_LOG_TRACE("Exploring state with id " << currentIndex << "."); storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(currentState, stateToIdCallback); @@ -384,6 +409,7 @@ namespace storm { } ++currentRow; + ++currentRowGroup; } else { std::cout << unpackStateIntoValuation(currentState).toString(true) << std::endl; STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, @@ -430,9 +456,40 @@ namespace storm { } ++currentRow; } + ++currentRowGroup; } } + // If the exploration order was not breadth-first, we need to fix the entries in the matrix according to + // (reversed) mapping of row groups to indices. + if (options.explorationOrder != ExplorationOrder::Bfs) { + STORM_LOG_ASSERT(stateRemapping, "Unable to fix columns without mapping."); + std::vector<uint_fast64_t> const& remapping = stateRemapping.get(); + + // We need to fix the following entities: + // (a) the transition matrix + // (b) the initial states + // (c) the hash map storing the mapping states -> ids + + // Fix (a). + transitionMatrixBuilder.replaceColumns(remapping, 0); + + // Fix (b). + std::vector<StateType> newInitialStateIndices(this->internalStateInformation.initialStateIndices.size()); + std::transform(this->internalStateInformation.initialStateIndices.begin(), this->internalStateInformation.initialStateIndices.end(), newInitialStateIndices.begin(), [&remapping] (StateType const& state) { return remapping[state]; } ); + std::sort(newInitialStateIndices.begin(), newInitialStateIndices.end()); + this->internalStateInformation.initialStateIndices = std::move(newInitialStateIndices); + + // Fix (c). + std::unordered_map<StateType, StateType> valueRemapping; + for (StateType index = 0; index < remapping.size(); ++index) { + if (remapping[index] != index) { + valueRemapping.emplace(index, static_cast<StateType>(remapping[index])); + } + } + this->internalStateInformation.stateStorage.remap(valueRemapping); + } + return choiceLabels; } diff --git a/src/builder/ExplicitPrismModelBuilder.h b/src/builder/ExplicitPrismModelBuilder.h index 3e5614854..ab2eb9815 100644 --- a/src/builder/ExplicitPrismModelBuilder.h +++ b/src/builder/ExplicitPrismModelBuilder.h @@ -1,5 +1,5 @@ -#ifndef STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H -#define STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H +#ifndef STORM_BUILDER_EXPLICITPRISMMODELBUILDER_H +#define STORM_BUILDER_EXPLICITPRISMMODELBUILDER_H #include <memory> #include <utility> @@ -24,6 +24,8 @@ #include "src/utility/prism.h" +#include "src/builder/ExplorationOrder.h" + #include "src/generator/CompressedState.h" #include "src/generator/VariableInformation.h" @@ -102,6 +104,11 @@ namespace storm { */ Options(); + /*! + * Copies the given set of options. + */ + Options(Options const& other) = default; + /*! Creates an object representing the suggested building options assuming that the given formula is the * only one to check. Additional formulas may be preserved by calling <code>preserveFormula</code>. * @@ -144,6 +151,9 @@ namespace storm { */ void setTerminalStatesFromFormula(storm::logic::Formula const& formula); + // The order in which to explore the model. + ExplorationOrder explorationOrder; + // A flag that indicates whether or not command labels are to be built. bool buildCommandLabels; @@ -286,13 +296,13 @@ namespace storm { // A set of states that still need to be explored. std::deque<CompressedState> statesToExplore; - // An optional mapping from row groups to the indices of the states that they reflect. This needs to be built - // in case the exploration order is not BFS. -// boost::optional<std::vector<StateType, StateType>> rowGroupToIndexMapping; + // An optional mapping from state indices to the row groups in which they actually reside. This needs to be + // built in case the exploration order is not BFS. + boost::optional<std::vector<uint_fast64_t>> stateRemapping; }; } // namespace adapters } // namespace storm -#endif /* STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H */ +#endif /* STORM_BUILDER_EXPLICITPRISMMODELBUILDER_H */ diff --git a/src/builder/ExplorationOrder.cpp b/src/builder/ExplorationOrder.cpp new file mode 100644 index 000000000..fb0b82766 --- /dev/null +++ b/src/builder/ExplorationOrder.cpp @@ -0,0 +1,22 @@ +#include "src/builder/ExplorationOrder.h" + +namespace storm { + namespace builder { + + std::ostream& operator<<(std::ostream& out, ExplorationOrder const& order) { + switch (order) { + case ExplorationOrder::Dfs: + out << "depth-first"; + break; + case ExplorationOrder::Bfs: + out << "breadth-first"; + break; + default: + out << "undefined"; + break; + } + return out; + } + + } +} \ No newline at end of file diff --git a/src/builder/ExplorationOrder.h b/src/builder/ExplorationOrder.h new file mode 100644 index 000000000..94c6363b3 --- /dev/null +++ b/src/builder/ExplorationOrder.h @@ -0,0 +1,17 @@ +#ifndef STORM_BUILDER_EXPLORATIONORDER_H_ +#define STORM_BUILDER_EXPLORATIONORDER_H_ + +#include <ostream> + +namespace storm { + namespace builder { + + // An enum that contains all currently supported exploration orders. + enum class ExplorationOrder { Dfs, Bfs }; + + std::ostream& operator<<(std::ostream& out, ExplorationOrder const& order); + + } +} + +#endif /* STORM_BUILDER_EXPLORATIONORDER_H_ */ \ No newline at end of file diff --git a/src/settings/modules/GeneralSettings.cpp b/src/settings/modules/GeneralSettings.cpp index 95a48931b..171b2a886 100644 --- a/src/settings/modules/GeneralSettings.cpp +++ b/src/settings/modules/GeneralSettings.cpp @@ -32,6 +32,8 @@ namespace storm { const std::string GeneralSettings::explicitOptionShortName = "exp"; const std::string GeneralSettings::symbolicOptionName = "symbolic"; const std::string GeneralSettings::symbolicOptionShortName = "s"; + const std::string GeneralSettings::explorationOrderOptionName = "explorder"; + const std::string GeneralSettings::explorationOrderOptionShortName = "eo"; const std::string GeneralSettings::propertyOptionName = "prop"; const std::string GeneralSettings::propertyOptionShortName = "prop"; const std::string GeneralSettings::transitionRewardsOptionName = "transrew"; @@ -83,6 +85,11 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("labeling filename", "The name of the file from which to read the state labeling.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, symbolicOptionName, false, "Parses the model given in a symbolic representation.").setShortName(symbolicOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the symbolic model.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build()); + + std::vector<std::string> explorationOrders = {"dfs", "bfs"}; + this->addOption(storm::settings::OptionBuilder(moduleName, explorationOrderOptionName, false, "Sets which exploration order to use.").setShortName(explorationOrderOptionShortName) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the exploration order to choose. Available are: dfs and bfs.").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator(explorationOrders)).setDefaultValueString("dfs").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, propertyOptionName, false, "Specifies the formulas to be checked on the model.").setShortName(propertyOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("formula or filename", "The formula or the file containing the formulas.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, counterexampleOptionName, false, "Generates a counterexample for the given PRCTL formulas if not satisfied by the model") @@ -186,6 +193,20 @@ namespace storm { return this->getOption(symbolicOptionName).getArgumentByName("filename").getValueAsString(); } + bool GeneralSettings::isExplorationOrderSet() const { + return this->getOption(explorationOrderOptionName).getHasOptionBeenSet(); + } + + storm::builder::ExplorationOrder GeneralSettings::getExplorationOrder() const { + std::string explorationOrderAsString = this->getOption(explorationOrderOptionName).getArgumentByName("name").getValueAsString(); + if (explorationOrderAsString == "dfs") { + return storm::builder::ExplorationOrder::Dfs; + } else if (explorationOrderAsString == "bfs") { + return storm::builder::ExplorationOrder::Bfs; + } + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown exploration order '" << explorationOrderAsString << "'."); + } + bool GeneralSettings::isPropertySet() const { return this->getOption(propertyOptionName).getHasOptionBeenSet(); } diff --git a/src/settings/modules/GeneralSettings.h b/src/settings/modules/GeneralSettings.h index 8144c0a1f..ad268db93 100644 --- a/src/settings/modules/GeneralSettings.h +++ b/src/settings/modules/GeneralSettings.h @@ -4,6 +4,8 @@ #include "storm-config.h" #include "src/settings/modules/ModuleSettings.h" +#include "src/builder/ExplorationOrder.h" + namespace storm { namespace solver { enum class EquationSolverType; @@ -25,7 +27,6 @@ namespace storm { class GeneralSettings : public ModuleSettings { public: // An enumeration of all engines. - enum class Engine { Sparse, Hybrid, Dd, AbstractionRefinement }; @@ -138,6 +139,20 @@ namespace storm { * @return The name of the file that contains the symbolic model specification. */ std::string getSymbolicModelFilename() const; + + /*! + * Retrieves whether the model exploration order was set. + * + * @return True if the model exploration option was set. + */ + bool isExplorationOrderSet() const; + + /*! + * Retrieves the exploration order if it was set. + * + * @return The chosen exploration order. + */ + storm::builder::ExplorationOrder getExplorationOrder() const; /*! * Retrieves whether the property option was set. @@ -389,6 +404,8 @@ namespace storm { static const std::string explicitOptionShortName; static const std::string symbolicOptionName; static const std::string symbolicOptionShortName; + static const std::string explorationOrderOptionName; + static const std::string explorationOrderOptionShortName; static const std::string propertyOptionName; static const std::string propertyOptionShortName; static const std::string transitionRewardsOptionName; diff --git a/src/storage/BitVectorHashMap.cpp b/src/storage/BitVectorHashMap.cpp index 881fc016a..fd4304eaa 100644 --- a/src/storage/BitVectorHashMap.cpp +++ b/src/storage/BitVectorHashMap.cpp @@ -233,6 +233,16 @@ namespace storm { return std::make_pair(buckets.get(bucket * bucketSize, bucketSize), values[bucket]); } + template<class ValueType, class Hash1, class Hash2> + void BitVectorHashMap<ValueType, Hash1, Hash2>::remap(std::unordered_map<ValueType, ValueType> const& remapping) { + for (auto pos : occupied) { + auto it = remapping.find(values[pos]); + if (it != remapping.end()) { + values[pos] = it->second; + } + } + } + template class BitVectorHashMap<uint_fast64_t>; template class BitVectorHashMap<uint32_t>; } diff --git a/src/storage/BitVectorHashMap.h b/src/storage/BitVectorHashMap.h index c53928b09..7e8a1dc0e 100644 --- a/src/storage/BitVectorHashMap.h +++ b/src/storage/BitVectorHashMap.h @@ -3,6 +3,7 @@ #include <cstdint> #include <functional> +#include <unordered_map> #include "src/storage/BitVector.h" @@ -123,6 +124,13 @@ namespace storm { */ std::size_t capacity() const; + /*! + * Performs a remapping of all values stored by applying the given remapping. + * + * @param remapping The remapping to apply. + */ + void remap(std::unordered_map<ValueType, ValueType> const& remapping); + private: /*! * Retrieves whether the given bucket holds a value. diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp index 3dbabf854..08138d48c 100644 --- a/src/storage/SparseMatrix.cpp +++ b/src/storage/SparseMatrix.cpp @@ -143,12 +143,12 @@ namespace storm { STORM_LOG_THROW(startingRow >= lastRow, storm::exceptions::InvalidStateException, "Illegal row group with negative size."); rowGroupIndices.push_back(startingRow); ++currentRowGroup; - + // Close all rows from the most recent one to the starting row. for (index_type i = lastRow + 1; i <= startingRow; ++i) { rowIndications.push_back(currentEntryCount); } - + // Reset the most recently seen row/column to allow for proper insertion of the following elements. lastRow = startingRow; lastColumn = 0; @@ -162,7 +162,7 @@ namespace storm { rowCount = std::max(rowCount, initialRowCount); } rowCount = std::max(rowCount, overriddenRowCount); - + // If the current row count was overridden, we may need to add empty rows. for (index_type i = lastRow + 1; i < rowCount; ++i) { rowIndications.push_back(currentEntryCount); @@ -202,7 +202,7 @@ namespace storm { rowGroupIndices.push_back(rowCount); } } - + return SparseMatrix<ValueType>(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), hasCustomRowGrouping); } @@ -216,6 +216,72 @@ namespace storm { return lastColumn; } + template<typename ValueType> + bool SparseMatrixBuilder<ValueType>::replaceColumns(std::vector<index_type> const& replacements, index_type offset) { + bool changed = false; + + // Sort columns per row. + typename SparseMatrix<ValueType>::index_type endGroups; + typename SparseMatrix<ValueType>::index_type endRows; + for (index_type group = 0; group < rowGroupIndices.size(); ++group) { + endGroups = group < rowGroupIndices.size()-1 ? rowGroupIndices[group+1] : rowIndications.size(); + for (index_type i = rowGroupIndices[group]; i < endGroups; ++i) { + bool changedRow = false; + endRows = i < rowIndications.size()-1 ? rowIndications[i+1] : columnsAndValues.size(); + + for (auto it = columnsAndValues.begin() + rowIndications[i], ite = columnsAndValues.begin() + endRows; it != ite; ++it) { + if (it->getColumn() >= offset) { + it->setColumn(replacements[it->getColumn() - offset]); + changedRow = true; + } + // Update highest column in a way that only works if the highest appearing index does not become + // lower during performing the replacement. + highestColumn = std::max(highestColumn, it->getColumn()); + } + + if (changedRow) { + changed = true; + + // Sort the row. + std::sort(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows, + [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) { + return a.getColumn() < b.getColumn(); + }); + // Assert no equal elements + STORM_LOG_ASSERT(std::is_sorted(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows, + [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) { + return a.getColumn() <= b.getColumn(); + }), "Must not have different elements with the same column in a row."); + } + } + } + + return changed; + } + + template<typename ValueType> + void SparseMatrixBuilder<ValueType>::fixColumns() { + // Sort columns per row. + typename SparseMatrix<ValueType>::index_type endGroups; + typename SparseMatrix<ValueType>::index_type endRows; + for (index_type group = 0; group < rowGroupIndices.size(); ++group) { + endGroups = group < rowGroupIndices.size()-1 ? rowGroupIndices[group+1] : rowIndications.size(); + for (index_type i = rowGroupIndices[group]; i < endGroups; ++i) { + endRows = i < rowIndications.size()-1 ? rowIndications[i+1] : columnsAndValues.size(); + // Sort the row. + std::sort(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows, + [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) { + return a.getColumn() < b.getColumn(); + }); + // Assert no equal elements + STORM_LOG_ASSERT(std::is_sorted(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows, + [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) { + return a.getColumn() <= b.getColumn(); + }), "Must not have different elements with the same column in a row."); + } + } + } + template<typename ValueType> SparseMatrix<ValueType>::rows::rows(iterator begin, index_type entryCount) : beginIterator(begin), entryCount(entryCount) { // Intentionally left empty. @@ -532,12 +598,12 @@ namespace storm { *it = i; } auto res = getSubmatrix(rowConstraint, columnConstraint, fakeRowGroupIndices, insertDiagonalElements); - + // Create a new row grouping that reflects the new sizes of the row groups. std::vector<uint_fast64_t> newRowGroupIndices; newRowGroupIndices.push_back(0); auto selectedRowIt = rowConstraint.begin(); - + // For this, we need to count how many rows were preserved in every group. for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) { uint_fast64_t newRowCount = 0; @@ -1172,7 +1238,7 @@ namespace storm { assert(this->getRowGroupSize(group) == 1); for (typename SparseMatrix<ValueType>::index_type i = this->getRowGroupIndices()[group]; i < this->getRowGroupIndices()[group + 1]; ++i) { typename SparseMatrix<ValueType>::index_type nextIndex = this->rowIndications[i]; - + // Print the actual row. out << i << "\t("; typename SparseMatrix<ValueType>::index_type currentRealIndex = 0; @@ -1226,7 +1292,7 @@ namespace storm { template std::ostream& operator<<(std::ostream& out, SparseMatrix<double> const& matrix); template std::vector<double> SparseMatrix<double>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<double> const& otherMatrix) const; template bool SparseMatrix<double>::isSubmatrixOf(SparseMatrix<double> const& matrix) const; - + // float template class MatrixEntry<typename SparseMatrix<float>::index_type, float>; template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<float>::index_type, float> const& entry); @@ -1235,7 +1301,7 @@ namespace storm { template std::ostream& operator<<(std::ostream& out, SparseMatrix<float> const& matrix); template std::vector<float> SparseMatrix<float>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<float> const& otherMatrix) const; template bool SparseMatrix<float>::isSubmatrixOf(SparseMatrix<float> const& matrix) const; - + // int template class MatrixEntry<typename SparseMatrix<int>::index_type, int>; template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<int>::index_type, int> const& entry); @@ -1243,7 +1309,7 @@ namespace storm { template class SparseMatrix<int>; template std::ostream& operator<<(std::ostream& out, SparseMatrix<int> const& matrix); template bool SparseMatrix<int>::isSubmatrixOf(SparseMatrix<int> const& matrix) const; - + // state_type template class MatrixEntry<typename SparseMatrix<storm::storage::sparse::state_type>::index_type, storm::storage::sparse::state_type>; template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<storm::storage::sparse::state_type>::index_type, storm::storage::sparse::state_type> const& entry); @@ -1251,7 +1317,7 @@ namespace storm { template class SparseMatrix<storm::storage::sparse::state_type>; template std::ostream& operator<<(std::ostream& out, SparseMatrix<storm::storage::sparse::state_type> const& matrix); template bool SparseMatrix<int>::isSubmatrixOf(SparseMatrix<storm::storage::sparse::state_type> const& matrix) const; - + #ifdef STORM_HAVE_CARL // Rat Function template class MatrixEntry<typename SparseMatrix<RationalFunction>::index_type, RationalFunction>; @@ -1264,7 +1330,7 @@ namespace storm { template std::vector<storm::RationalFunction> SparseMatrix<float>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::RationalFunction> const& otherMatrix) const; template std::vector<storm::RationalFunction> SparseMatrix<int>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::RationalFunction> const& otherMatrix) const; template bool SparseMatrix<storm::RationalFunction>::isSubmatrixOf(SparseMatrix<storm::RationalFunction> const& matrix) const; - + // Intervals template std::vector<storm::Interval> SparseMatrix<double>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::Interval> const& otherMatrix) const; template class MatrixEntry<typename SparseMatrix<Interval>::index_type, Interval>; @@ -1274,7 +1340,7 @@ namespace storm { template std::ostream& operator<<(std::ostream& out, SparseMatrix<Interval> const& matrix); template std::vector<storm::Interval> SparseMatrix<Interval>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::Interval> const& otherMatrix) const; template bool SparseMatrix<storm::Interval>::isSubmatrixOf(SparseMatrix<storm::Interval> const& matrix) const; - + template bool SparseMatrix<storm::Interval>::isSubmatrixOf(SparseMatrix<double> const& matrix) const; #endif diff --git a/src/storage/SparseMatrix.h b/src/storage/SparseMatrix.h index f9d9916c4..4892dbe32 100644 --- a/src/storage/SparseMatrix.h +++ b/src/storage/SparseMatrix.h @@ -217,6 +217,17 @@ namespace storm { */ index_type getLastColumn() const; + /*! + * Replaces all columns with id > offset according to replacements. + * Every state with id offset+i is replaced by the id in replacements[i]. + * Afterwards the columns are sorted. + * + * @param replacements Mapping indicating the replacements from offset+i -> value of i. + * @param offset Offset to add to each id in vector index. + * @return True if replacement took place, False if nothing changed. + */ + bool replaceColumns(std::vector<index_type> const& replacements, index_type offset); + private: // A flag indicating whether a row count was set upon construction. bool initialRowCountSet; @@ -277,6 +288,11 @@ namespace storm { // Stores the currently active row group. This is used for correctly constructing the row grouping of the // matrix. index_type currentRowGroup; + + /*! + * Fixes the matrix by sorting the columns to gain increasing order again. + */ + void fixColumns(); }; /*! diff --git a/src/storage/prism/RewardModel.cpp b/src/storage/prism/RewardModel.cpp index 3f38f7bd8..30c43728c 100644 --- a/src/storage/prism/RewardModel.cpp +++ b/src/storage/prism/RewardModel.cpp @@ -84,7 +84,7 @@ namespace storm { std::ostream& operator<<(std::ostream& stream, RewardModel const& rewardModel) { stream << "rewards"; if (rewardModel.getName() != "") { - std::cout << " \"" << rewardModel.getName() << "\""; + stream << " \"" << rewardModel.getName() << "\""; } stream << std::endl; for (auto const& reward : rewardModel.getStateRewards()) { diff --git a/src/utility/constants.cpp b/src/utility/constants.cpp index 900482a72..941f07f7e 100644 --- a/src/utility/constants.cpp +++ b/src/utility/constants.cpp @@ -192,6 +192,10 @@ namespace storm { template bool isZero(storm::storage::sparse::state_type const& value); template bool isConstant(storm::storage::sparse::state_type const& value); + template uint32_t one(); + template uint32_t zero(); + template uint32_t infinity(); + template storm::storage::sparse::state_type one(); template storm::storage::sparse::state_type zero(); template storm::storage::sparse::state_type infinity(); From ffe63ea95d63b2bdcbf49573b0217acefcd28ba7 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 29 Feb 2016 22:10:30 +0100 Subject: [PATCH 11/33] made dfs as exploration order available Former-commit-id: 46ea31af78b5819690fcc0a47ef9c1565c109c2b --- src/builder/ExplicitPrismModelBuilder.cpp | 12 +--- src/parser/PrismParser.cpp | 4 +- src/settings/ArgumentValidators.h | 16 ++++-- src/storage/BitVectorHashMap.cpp | 7 +-- src/storage/BitVectorHashMap.h | 3 +- src/storage/SparseMatrix.cpp | 70 +++++++---------------- src/storage/SparseMatrix.h | 5 -- 7 files changed, 40 insertions(+), 77 deletions(-) diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp index 1aeab458d..1ef7f3ad8 100644 --- a/src/builder/ExplicitPrismModelBuilder.cpp +++ b/src/builder/ExplicitPrismModelBuilder.cpp @@ -231,8 +231,8 @@ namespace storm { } // Now that the program is fixed, we we need to substitute all constants with their concrete value. - this->program = program.substituteConstants(); - + this->program = this->program.substituteConstants(); + // Create the variable information for the transformed program. this->variableInformation = VariableInformation(this->program); @@ -481,13 +481,7 @@ namespace storm { this->internalStateInformation.initialStateIndices = std::move(newInitialStateIndices); // Fix (c). - std::unordered_map<StateType, StateType> valueRemapping; - for (StateType index = 0; index < remapping.size(); ++index) { - if (remapping[index] != index) { - valueRemapping.emplace(index, static_cast<StateType>(remapping[index])); - } - } - this->internalStateInformation.stateStorage.remap(valueRemapping); + this->internalStateInformation.stateStorage.remap([&remapping] (StateType const& state) { return remapping[state]; } ); } return choiceLabels; diff --git a/src/parser/PrismParser.cpp b/src/parser/PrismParser.cpp index 9040f3cf4..b2a153f99 100644 --- a/src/parser/PrismParser.cpp +++ b/src/parser/PrismParser.cpp @@ -11,7 +11,7 @@ namespace storm { namespace parser { storm::prism::Program PrismParser::parse(std::string const& filename) { // Open file and initialize result. - std::ifstream inputFileStream(filename, std::ios::in); + std::ifstream inputFileStream(filename); STORM_LOG_THROW(inputFileStream.good(), storm::exceptions::WrongFormatException, "Unable to read from file '" << filename << "'."); storm::prism::Program result; @@ -35,7 +35,7 @@ namespace storm { PositionIteratorType first(input.begin()); PositionIteratorType iter = first; PositionIteratorType last(input.end()); - assert(first != last); + STORM_LOG_ASSERT(first != last, "Illegal input to PRISM parser."); // Create empty result; storm::prism::Program result; diff --git a/src/settings/ArgumentValidators.h b/src/settings/ArgumentValidators.h index 235ddd765..6e1b4aa02 100644 --- a/src/settings/ArgumentValidators.h +++ b/src/settings/ArgumentValidators.h @@ -18,6 +18,7 @@ #include "src/exceptions/IllegalArgumentValueException.h" #include "src/exceptions/IllegalFunctionCallException.h" +#include <sys/stat.h> namespace storm { namespace settings { @@ -97,11 +98,16 @@ namespace storm { */ static std::function<bool (std::string const&)> existingReadableFileValidator() { return [] (std::string const fileName) -> bool { - std::ifstream targetFile(fileName); - bool isFileGood = targetFile.good(); - - STORM_LOG_THROW(isFileGood, storm::exceptions::IllegalArgumentValueException, "The file " << fileName << " does not exist or is not readable."); - return isFileGood; + // First check existence as ifstream::good apparently als returns true for directories. + struct stat info; + stat(fileName.c_str(), &info); + STORM_LOG_THROW(info.st_mode & S_IFREG, storm::exceptions::IllegalArgumentValueException, "Unable to read from non-existing file '" << fileName << "'."); + + // Now that we know it's a file, we can check its readability. + std::ifstream istream(fileName); + STORM_LOG_THROW(istream.good(), storm::exceptions::IllegalArgumentValueException, "Unable to read from file '" << fileName << "'."); + + return true; }; } diff --git a/src/storage/BitVectorHashMap.cpp b/src/storage/BitVectorHashMap.cpp index fd4304eaa..66ff43f96 100644 --- a/src/storage/BitVectorHashMap.cpp +++ b/src/storage/BitVectorHashMap.cpp @@ -234,12 +234,9 @@ namespace storm { } template<class ValueType, class Hash1, class Hash2> - void BitVectorHashMap<ValueType, Hash1, Hash2>::remap(std::unordered_map<ValueType, ValueType> const& remapping) { + void BitVectorHashMap<ValueType, Hash1, Hash2>::remap(std::function<ValueType(ValueType const&)> const& remapping) { for (auto pos : occupied) { - auto it = remapping.find(values[pos]); - if (it != remapping.end()) { - values[pos] = it->second; - } + values[pos] = remapping(values[pos]); } } diff --git a/src/storage/BitVectorHashMap.h b/src/storage/BitVectorHashMap.h index 7e8a1dc0e..746467203 100644 --- a/src/storage/BitVectorHashMap.h +++ b/src/storage/BitVectorHashMap.h @@ -3,7 +3,6 @@ #include <cstdint> #include <functional> -#include <unordered_map> #include "src/storage/BitVector.h" @@ -129,7 +128,7 @@ namespace storm { * * @param remapping The remapping to apply. */ - void remap(std::unordered_map<ValueType, ValueType> const& remapping); + void remap(std::function<ValueType(ValueType const&)> const& remapping); private: /*! diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp index 08138d48c..9d390185f 100644 --- a/src/storage/SparseMatrix.cpp +++ b/src/storage/SparseMatrix.cpp @@ -218,68 +218,40 @@ namespace storm { template<typename ValueType> bool SparseMatrixBuilder<ValueType>::replaceColumns(std::vector<index_type> const& replacements, index_type offset) { - bool changed = false; + bool matrixChanged = false; - // Sort columns per row. - typename SparseMatrix<ValueType>::index_type endGroups; - typename SparseMatrix<ValueType>::index_type endRows; - for (index_type group = 0; group < rowGroupIndices.size(); ++group) { - endGroups = group < rowGroupIndices.size()-1 ? rowGroupIndices[group+1] : rowIndications.size(); - for (index_type i = rowGroupIndices[group]; i < endGroups; ++i) { - bool changedRow = false; - endRows = i < rowIndications.size()-1 ? rowIndications[i+1] : columnsAndValues.size(); - - for (auto it = columnsAndValues.begin() + rowIndications[i], ite = columnsAndValues.begin() + endRows; it != ite; ++it) { - if (it->getColumn() >= offset) { - it->setColumn(replacements[it->getColumn() - offset]); - changedRow = true; - } - // Update highest column in a way that only works if the highest appearing index does not become - // lower during performing the replacement. - highestColumn = std::max(highestColumn, it->getColumn()); - } - - if (changedRow) { - changed = true; - - // Sort the row. - std::sort(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows, - [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) { - return a.getColumn() < b.getColumn(); - }); - // Assert no equal elements - STORM_LOG_ASSERT(std::is_sorted(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows, - [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) { - return a.getColumn() <= b.getColumn(); - }), "Must not have different elements with the same column in a row."); + // Walk through all rows. + for (index_type row = 0; row < rowIndications.size(); ++row) { + bool rowChanged = false; + index_type rowEnd = row < rowIndications.size()-1 ? rowIndications[row+1] : columnsAndValues.size(); + + for (auto it = columnsAndValues.begin() + rowIndications[row], ite = columnsAndValues.begin() + rowEnd; it != ite; ++it) { + if (it->getColumn() >= offset && it->getColumn() != replacements[it->getColumn() - offset]) { + it->setColumn(replacements[it->getColumn() - offset]); + rowChanged = true; } + // Update highest column in a way that only works if the highest appearing index does not become + // lower during performing the replacement. + highestColumn = std::max(highestColumn, it->getColumn()); } - } - - return changed; - } - - template<typename ValueType> - void SparseMatrixBuilder<ValueType>::fixColumns() { - // Sort columns per row. - typename SparseMatrix<ValueType>::index_type endGroups; - typename SparseMatrix<ValueType>::index_type endRows; - for (index_type group = 0; group < rowGroupIndices.size(); ++group) { - endGroups = group < rowGroupIndices.size()-1 ? rowGroupIndices[group+1] : rowIndications.size(); - for (index_type i = rowGroupIndices[group]; i < endGroups; ++i) { - endRows = i < rowIndications.size()-1 ? rowIndications[i+1] : columnsAndValues.size(); + + if (rowChanged) { + matrixChanged = true; + // Sort the row. - std::sort(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows, + std::sort(columnsAndValues.begin() + rowIndications[row], columnsAndValues.begin() + rowEnd, [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) { return a.getColumn() < b.getColumn(); }); // Assert no equal elements - STORM_LOG_ASSERT(std::is_sorted(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows, + STORM_LOG_ASSERT(std::is_sorted(columnsAndValues.begin() + rowIndications[row], columnsAndValues.begin() + rowEnd, [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) { return a.getColumn() <= b.getColumn(); }), "Must not have different elements with the same column in a row."); } } + + return matrixChanged; } template<typename ValueType> diff --git a/src/storage/SparseMatrix.h b/src/storage/SparseMatrix.h index 4892dbe32..1ecee566f 100644 --- a/src/storage/SparseMatrix.h +++ b/src/storage/SparseMatrix.h @@ -288,11 +288,6 @@ namespace storm { // Stores the currently active row group. This is used for correctly constructing the row grouping of the // matrix. index_type currentRowGroup; - - /*! - * Fixes the matrix by sorting the columns to gain increasing order again. - */ - void fixColumns(); }; /*! From c45812c66ae44a62ef41b2921915c2d0f5544164 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 1 Mar 2016 19:22:08 +0100 Subject: [PATCH 12/33] made bfs the default exploration order again Former-commit-id: 6476c48a6798c7a48343da7626e27d28fe57ace5 --- src/settings/modules/GeneralSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings/modules/GeneralSettings.cpp b/src/settings/modules/GeneralSettings.cpp index 171b2a886..9979c6824 100644 --- a/src/settings/modules/GeneralSettings.cpp +++ b/src/settings/modules/GeneralSettings.cpp @@ -88,7 +88,7 @@ namespace storm { std::vector<std::string> explorationOrders = {"dfs", "bfs"}; this->addOption(storm::settings::OptionBuilder(moduleName, explorationOrderOptionName, false, "Sets which exploration order to use.").setShortName(explorationOrderOptionShortName) - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the exploration order to choose. Available are: dfs and bfs.").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator(explorationOrders)).setDefaultValueString("dfs").build()).build()); + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the exploration order to choose. Available are: dfs and bfs.").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator(explorationOrders)).setDefaultValueString("bfs").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, propertyOptionName, false, "Specifies the formulas to be checked on the model.").setShortName(propertyOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("formula or filename", "The formula or the file containing the formulas.").build()).build()); From 1f5439e270fda649a63f6be8f4fdf75cad829eda Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Sun, 6 Mar 2016 20:08:53 +0100 Subject: [PATCH 13/33] added state labeling generator interface Former-commit-id: eb7668741fa1561dbb2bd3c043a7b4b5674327fe --- src/builder/ExplicitPrismModelBuilder.cpp | 30 ++--------- src/generator/NextStateGenerator.h | 2 +- src/generator/PrismNextStateGenerator.h | 2 +- src/generator/PrismStateLabelingGenerator.cpp | 50 +++++++++++++++++++ src/generator/PrismStateLabelingGenerator.h | 31 ++++++++++++ src/generator/StateLabelingGenerator.h | 20 ++++++++ 6 files changed, 106 insertions(+), 29 deletions(-) create mode 100644 src/generator/PrismStateLabelingGenerator.cpp create mode 100644 src/generator/PrismStateLabelingGenerator.h create mode 100644 src/generator/StateLabelingGenerator.h diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp index 1ef7f3ad8..ef53b9e43 100644 --- a/src/builder/ExplicitPrismModelBuilder.cpp +++ b/src/builder/ExplicitPrismModelBuilder.cpp @@ -12,6 +12,7 @@ #include "src/settings/modules/GeneralSettings.h" #include "src/generator/PrismNextStateGenerator.h" +#include "src/generator/PrismStateLabelingGenerator.h" #include "src/utility/prism.h" #include "src/utility/constants.h" @@ -558,33 +559,8 @@ namespace storm { template <typename ValueType, typename RewardModelType, typename StateType> storm::models::sparse::StateLabeling ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildStateLabeling() { - std::vector<storm::prism::Label> const& labels = program.getLabels(); - - storm::expressions::ExpressionEvaluator<ValueType> evaluator(program.getManager()); - storm::models::sparse::StateLabeling result(internalStateInformation.numberOfStates); - - // Initialize labeling. - for (auto const& label : labels) { - result.addLabel(label.getName()); - } - for (auto const& stateIndexPair : internalStateInformation.stateStorage) { - unpackStateIntoEvaluator(stateIndexPair.first, variableInformation, evaluator); - - for (auto const& label : labels) { - // Add label to state, if the corresponding expression is true. - if (evaluator.asBool(label.getStatePredicateExpression())) { - result.addLabelToState(label.getName(), stateIndexPair.second); - } - } - } - - // Also label the initial state with the special label "init". - result.addLabel("init"); - for (auto index : internalStateInformation.initialStateIndices) { - result.addLabelToState("init", index); - } - - return result; + storm::generator::PrismStateLabelingGenerator<ValueType, StateType> generator(program, variableInformation); + return generator.generate(internalStateInformation.stateStorage, internalStateInformation.initialStateIndices); } // Explicitly instantiate the class. diff --git a/src/generator/NextStateGenerator.h b/src/generator/NextStateGenerator.h index f70709779..779a49ef3 100644 --- a/src/generator/NextStateGenerator.h +++ b/src/generator/NextStateGenerator.h @@ -21,4 +21,4 @@ namespace storm { } } -#endif \ No newline at end of file +#endif /* STORM_GENERATOR_NEXTSTATEGENERATOR_H_ */ \ No newline at end of file diff --git a/src/generator/PrismNextStateGenerator.h b/src/generator/PrismNextStateGenerator.h index e9c63502e..d8eddc0ac 100644 --- a/src/generator/PrismNextStateGenerator.h +++ b/src/generator/PrismNextStateGenerator.h @@ -92,7 +92,7 @@ namespace storm { // An optional expression that governs which states must not be explored. boost::optional<storm::expressions::Expression> terminalExpression; - // Information about how the variables are packed + // Information about how the variables are packed. VariableInformation const& variableInformation; // An evaluator used to evaluate expressions. diff --git a/src/generator/PrismStateLabelingGenerator.cpp b/src/generator/PrismStateLabelingGenerator.cpp new file mode 100644 index 000000000..6022ce063 --- /dev/null +++ b/src/generator/PrismStateLabelingGenerator.cpp @@ -0,0 +1,50 @@ +#include "src/generator/PrismStateLabelingGenerator.h" + +#include "src/generator/CompressedState.h" + +#include "src/storage/expressions/ExpressionEvaluator.h" + +namespace storm { + namespace generator { + + template<typename ValueType, typename StateType> + PrismStateLabelingGenerator<ValueType, StateType>::PrismStateLabelingGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation) : program(program), variableInformation(variableInformation) { + // Intentionally left empty. + } + + template<typename ValueType, typename StateType> + storm::models::sparse::StateLabeling PrismStateLabelingGenerator<ValueType, StateType>::generate(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices) { + std::vector<storm::prism::Label> const& labels = program.getLabels(); + + storm::expressions::ExpressionEvaluator<ValueType> evaluator(program.getManager()); + storm::models::sparse::StateLabeling result(states.size()); + + // Initialize labeling. + for (auto const& label : labels) { + result.addLabel(label.getName()); + } + for (auto const& stateIndexPair : states) { + unpackStateIntoEvaluator(stateIndexPair.first, variableInformation, evaluator); + + for (auto const& label : labels) { + // Add label to state, if the corresponding expression is true. + if (evaluator.asBool(label.getStatePredicateExpression())) { + result.addLabelToState(label.getName(), stateIndexPair.second); + } + } + } + + // Also label the initial state with the special label "init". + result.addLabel("init"); + for (auto index : initialStateIndices) { + result.addLabelToState("init", index); + } + + return result; + } + + template class PrismStateLabelingGenerator<double, uint32_t>; + template class PrismStateLabelingGenerator<storm::RationalFunction, uint32_t>; + + } +} \ No newline at end of file diff --git a/src/generator/PrismStateLabelingGenerator.h b/src/generator/PrismStateLabelingGenerator.h new file mode 100644 index 000000000..9859453ba --- /dev/null +++ b/src/generator/PrismStateLabelingGenerator.h @@ -0,0 +1,31 @@ +#ifndef STORM_GENERATOR_PRISMSTATELABELINGGENERATOR_H_ +#define STORM_GENERATOR_PRISMSTATELABELINGGENERATOR_H_ + +#include "src/generator/StateLabelingGenerator.h" + +#include "src/generator/VariableInformation.h" + +#include "src/storage/prism/Program.h" + +namespace storm { + namespace generator { + + template<typename ValueType, typename StateType = uint32_t> + class PrismStateLabelingGenerator : public StateLabelingGenerator<StateType> { + public: + PrismStateLabelingGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation); + + virtual storm::models::sparse::StateLabeling generate(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices = {}) override; + + private: + // The program for which to generate the labels. + storm::prism::Program const& program; + + // Information about how the variables are packed. + VariableInformation const& variableInformation; + }; + + } +} + +#endif /* STORM_GENERATOR_PRISMSTATELABELINGGENERATOR_H_ */ \ No newline at end of file diff --git a/src/generator/StateLabelingGenerator.h b/src/generator/StateLabelingGenerator.h new file mode 100644 index 000000000..17401c703 --- /dev/null +++ b/src/generator/StateLabelingGenerator.h @@ -0,0 +1,20 @@ +#ifndef STORM_GENERATOR_STATELABELINGGENERATOR_H_ +#define STORM_GENERATOR_STATELABELINGGENERATOR_H_ + +#include "src/models/sparse/StateLabeling.h" + +#include "src/storage/BitVectorHashMap.h" + +namespace storm { + namespace generator { + + template<typename StateType = uint32_t> + class StateLabelingGenerator { + public: + virtual storm::models::sparse::StateLabeling generate(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices = {}) = 0; + }; + + } +} + +#endif /* STORM_GENERATOR_STATELABELINGGENERATOR_H_ */ \ No newline at end of file From f81ce1cac193a01fab313dd4a7a6ce4cf6abd9e2 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 7 Mar 2016 16:07:40 +0100 Subject: [PATCH 14/33] started making row grouping optional Former-commit-id: b90ae91e754087bc55f35993b66713ab60edc7e5 --- src/storage/SparseMatrix.cpp | 198 ++++++++++++++++++++++------------- src/storage/SparseMatrix.h | 46 ++++---- 2 files changed, 148 insertions(+), 96 deletions(-) diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp index 9d390185f..83bc7dc83 100644 --- a/src/storage/SparseMatrix.cpp +++ b/src/storage/SparseMatrix.cpp @@ -80,8 +80,9 @@ namespace storm { if (initialEntryCountSet) { columnsAndValues.reserve(initialEntryCount); } - if (initialRowGroupCountSet) { - rowGroupIndices.reserve(initialRowGroupCount + 1); + if (initialRowGroupCountSet && hasCustomRowGrouping) { + rowGroupIndices = std::vector<index_type>(); + rowGroupIndices.get().reserve(initialRowGroupCount + 1); } rowIndications.push_back(0); } @@ -92,8 +93,8 @@ namespace storm { // If the matrix has a custom row grouping, we move it and remove the last element to make it 'open' again. if (hasCustomRowGrouping) { rowGroupIndices = std::move(matrix.rowGroupIndices); - rowGroupIndices.pop_back(); - currentRowGroup = rowGroupIndices.size() - 1; + rowGroupIndices.get().pop_back(); + currentRowGroup = rowGroupIndices.get().size() - 1; } // Likewise, we need to 'open' the row indications again. @@ -141,7 +142,7 @@ namespace storm { void SparseMatrixBuilder<ValueType>::newRowGroup(index_type startingRow) { STORM_LOG_THROW(hasCustomRowGrouping, storm::exceptions::InvalidStateException, "Matrix was not created to have a custom row grouping."); STORM_LOG_THROW(startingRow >= lastRow, storm::exceptions::InvalidStateException, "Illegal row group with negative size."); - rowGroupIndices.push_back(startingRow); + rowGroupIndices.get().push_back(startingRow); ++currentRowGroup; // Close all rows from the most recent one to the starting row. @@ -186,11 +187,7 @@ namespace storm { } // Check whether row groups are missing some entries. - if (!hasCustomRowGrouping) { - for (index_type i = 0; i <= rowCount; ++i) { - rowGroupIndices.push_back(i); - } - } else { + if (hasCustomRowGrouping) { uint_fast64_t rowGroupCount = currentRowGroup; if (initialRowGroupCountSet && forceInitialDimensions) { STORM_LOG_THROW(rowGroupCount <= initialRowGroupCount, storm::exceptions::InvalidStateException, "Expected not more than " << initialRowGroupCount << " row groups, but got " << rowGroupCount << "."); @@ -199,7 +196,7 @@ namespace storm { rowGroupCount = std::max(rowGroupCount, overriddenRowGroupCount); for (index_type i = currentRowGroup; i <= rowGroupCount; ++i) { - rowGroupIndices.push_back(rowCount); + rowGroupIndices.get().push_back(rowCount); } } @@ -295,12 +292,12 @@ namespace storm { } template<typename ValueType> - SparseMatrix<ValueType>::SparseMatrix() : rowCount(0), columnCount(0), entryCount(0), nonzeroEntryCount(0), columnsAndValues(), rowIndications(), nontrivialRowGrouping(false), rowGroupIndices() { + SparseMatrix<ValueType>::SparseMatrix() : rowCount(0), columnCount(0), entryCount(0), nonzeroEntryCount(0), columnsAndValues(), rowIndications(), rowGroupIndices() { // Intentionally left empty. } template<typename ValueType> - SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType> const& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), nontrivialRowGrouping(other.nontrivialRowGrouping), rowGroupIndices(other.rowGroupIndices) { + SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType> const& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), rowGroupIndices(other.rowGroupIndices) { // Intentionally left empty. } @@ -312,7 +309,7 @@ namespace storm { } template<typename ValueType> - SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType>&& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), nontrivialRowGrouping(other.nontrivialRowGrouping), rowGroupIndices(std::move(other.rowGroupIndices)) { + SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType>&& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), rowGroupIndices(std::move(other.rowGroupIndices)) { // Now update the source matrix other.rowCount = 0; other.columnCount = 0; @@ -320,12 +317,12 @@ namespace storm { } template<typename ValueType> - SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, ValueType>> const& columnsAndValues, std::vector<index_type> const& rowGroupIndices, bool nontrivialRowGrouping) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(columnsAndValues), rowIndications(rowIndications), nontrivialRowGrouping(nontrivialRowGrouping), rowGroupIndices(rowGroupIndices) { + SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, ValueType>> const& columnsAndValues, boost::optional<std::vector<index_type>> const& rowGroupIndices) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(columnsAndValues), rowIndications(rowIndications), trivialRowGrouping(!rowGroupIndices), rowGroupIndices(rowGroupIndices) { this->updateNonzeroEntryCount(); } template<typename ValueType> - SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, ValueType>>&& columnsAndValues, std::vector<index_type>&& rowGroupIndices, bool nontrivialRowGrouping) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), nontrivialRowGrouping(nontrivialRowGrouping), rowGroupIndices(std::move(rowGroupIndices)) { + SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, ValueType>>&& columnsAndValues, boost::optional<std::vector<index_type>>&& rowGroupIndices, bool nontrivialRowGrouping) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), trivialRowGrouping(!rowGroupIndices), rowGroupIndices(std::move(rowGroupIndices)) { this->updateNonzeroEntryCount(); } @@ -341,7 +338,7 @@ namespace storm { columnsAndValues = other.columnsAndValues; rowIndications = other.rowIndications; rowGroupIndices = other.rowGroupIndices; - nontrivialRowGrouping = other.nontrivialRowGrouping; + trivialRowGrouping = other.trivialRowGrouping; } return *this; @@ -359,7 +356,7 @@ namespace storm { columnsAndValues = std::move(other.columnsAndValues); rowIndications = std::move(other.rowIndications); rowGroupIndices = std::move(other.rowGroupIndices); - nontrivialRowGrouping = other.nontrivialRowGrouping; + trivialRowGrouping = other.trivialRowGrouping; } return *this; @@ -381,7 +378,11 @@ namespace storm { if (!equalityResult) { return false; } - equalityResult &= this->getRowGroupIndices() == other.getRowGroupIndices(); + if (!this->hasTrivialRowGrouping() && !other.hasTrivialRowGrouping()) { + equalityResult &= this->getRowGroupIndices() == other.getRowGroupIndices(); + } else { + equalityResult &= this->hasTrivialRowGrouping() && other.hasTrivialRowGrouping(); + } if (!equalityResult) { return false; } @@ -433,8 +434,12 @@ namespace storm { template<typename T> uint_fast64_t SparseMatrix<T>::getRowGroupEntryCount(uint_fast64_t const group) const { uint_fast64_t result = 0; - for (uint_fast64_t row = this->getRowGroupIndices()[group]; row < this->getRowGroupIndices()[group + 1]; ++row) { - result += (this->rowIndications[row + 1] - this->rowIndications[row]); + if (!this->hasTrivialRowGrouping()) { + for (uint_fast64_t row = this->getRowGroupIndices()[group]; row < this->getRowGroupIndices()[group + 1]; ++row) { + result += (this->rowIndications[row + 1] - this->rowIndications[row]); + } + } else { + result += (this->rowIndications[group + 1] - this->rowIndications[group]); } return result; } @@ -473,7 +478,11 @@ namespace storm { template<typename ValueType> typename SparseMatrix<ValueType>::index_type SparseMatrix<ValueType>::getRowGroupCount() const { - return rowGroupIndices.size() - 1; + if (!this->hasTrivialRowGrouping()) { + return rowGroupIndices.get().size() - 1; + } else { + return rowCount; + } } template<typename ValueType> @@ -483,7 +492,15 @@ namespace storm { template<typename ValueType> std::vector<typename SparseMatrix<ValueType>::index_type> const& SparseMatrix<ValueType>::getRowGroupIndices() const { - return rowGroupIndices; + // If there is no current row grouping, we need to create it. + if (!this->rowGroupIndices) { + STORM_LOG_ASSERT(trivialRowGrouping, "Only trivial row-groupings can be constructed on-the-fly."); + this->rowGroupIndices = std::vector<index_type>(this->getRowCount() + 1); + for (uint_fast64_t group = 0; group < this->getRowCount(); ++group) { + this->rowGroupIndices.get()[group] = group; + } + } + return rowGroupIndices.get(); } template<typename ValueType> @@ -495,9 +512,15 @@ namespace storm { template<typename ValueType> void SparseMatrix<ValueType>::makeRowGroupsAbsorbing(storm::storage::BitVector const& rowGroupConstraint) { - for (auto rowGroup : rowGroupConstraint) { - for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) { - makeRowDirac(row, rowGroup); + if (!this->hasTrivialRowGrouping()) { + for (auto rowGroup : rowGroupConstraint) { + for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) { + makeRowDirac(row, rowGroup); + } + } + } else { + for (auto rowGroup : rowGroupConstraint) { + makeRowDirac(rowGroup, rowGroup); } } } @@ -550,9 +573,15 @@ namespace storm { std::vector<ValueType> SparseMatrix<ValueType>::getConstrainedRowGroupSumVector(storm::storage::BitVector const& rowGroupConstraint, storm::storage::BitVector const& columnConstraint) const { std::vector<ValueType> result; result.reserve(rowGroupConstraint.getNumberOfSetBits()); - for (auto rowGroup : rowGroupConstraint) { - for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) { - result.push_back(getConstrainedRowSum(row, columnConstraint)); + if (!this->hasTrivialRowGrouping()) { + for (auto rowGroup : rowGroupConstraint) { + for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) { + result.push_back(getConstrainedRowSum(row, columnConstraint)); + } + } + } else { + for (auto rowGroup : rowGroupConstraint) { + result.push_back(getConstrainedRowSum(rowGroup, columnConstraint)); } } return result; @@ -571,24 +600,29 @@ namespace storm { } auto res = getSubmatrix(rowConstraint, columnConstraint, fakeRowGroupIndices, insertDiagonalElements); - // Create a new row grouping that reflects the new sizes of the row groups. - std::vector<uint_fast64_t> newRowGroupIndices; - newRowGroupIndices.push_back(0); - auto selectedRowIt = rowConstraint.begin(); - - // For this, we need to count how many rows were preserved in every group. - for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) { - uint_fast64_t newRowCount = 0; - while (*selectedRowIt < this->getRowGroupIndices()[group + 1]) { - ++selectedRowIt; - ++newRowCount; - } - if (newRowCount > 0) { - newRowGroupIndices.push_back(newRowGroupIndices.back() + newRowCount); + // Create a new row grouping that reflects the new sizes of the row groups if the current matrix has a + // non trivial row-grouping. + if (!this->hasTrivialRowGrouping()) { + std::vector<uint_fast64_t> newRowGroupIndices; + newRowGroupIndices.push_back(0); + auto selectedRowIt = rowConstraint.begin(); + + // For this, we need to count how many rows were preserved in every group. + for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) { + uint_fast64_t newRowCount = 0; + while (*selectedRowIt < this->getRowGroupIndices()[group + 1]) { + ++selectedRowIt; + ++newRowCount; + } + if (newRowCount > 0) { + newRowGroupIndices.push_back(newRowGroupIndices.back() + newRowCount); + } } + + res.trivialRowGrouping = false; + res.rowGroupIndices = newRowGroupIndices; } - res.rowGroupIndices = newRowGroupIndices; return res; } } @@ -635,13 +669,13 @@ namespace storm { } // Create and initialize resulting matrix. - SparseMatrixBuilder<ValueType> matrixBuilder(subRows, submatrixColumnCount, subEntries, true, this->hasNontrivialRowGrouping()); + SparseMatrixBuilder<ValueType> matrixBuilder(subRows, submatrixColumnCount, subEntries, true, !this->hasTrivialRowGrouping()); // Copy over selected entries. rowGroupCount = 0; index_type rowCount = 0; for (auto index : rowGroupConstraint) { - if (this->hasNontrivialRowGrouping()) { + if (!this->hasTrivialRowGrouping()) { matrixBuilder.newRowGroup(rowCount); } for (index_type i = rowGroupIndices[index]; i < rowGroupIndices[index + 1]; ++i) { @@ -677,12 +711,12 @@ namespace storm { template<typename ValueType> SparseMatrix<ValueType> SparseMatrix<ValueType>::restrictRows(storm::storage::BitVector const& rowsToKeep) const { // For now, we use the expensive call to submatrix. - assert(rowsToKeep.size() == getRowCount()); - assert(rowsToKeep.getNumberOfSetBits() >= getRowGroupCount()); + STORM_LOG_ASSERT(rowsToKeep.size() == this->getRowCount(), "Dimensions mismatch."); + STORM_LOG_ASSERT(rowsToKeep.getNumberOfSetBits() >= this->getRowGroupCount(), "Invalid dimensions."); SparseMatrix<ValueType> res(getSubmatrix(false, rowsToKeep, storm::storage::BitVector(getColumnCount(), true), false)); - assert(res.getRowCount() == rowsToKeep.getNumberOfSetBits()); - assert(res.getColumnCount() == getColumnCount()); - assert(getRowGroupCount() == res.getRowGroupCount()); + STORM_LOG_ASSERT(res.getRowCount() == rowsToKeep.getNumberOfSetBits(), "Invalid dimensions"); + STORM_LOG_ASSERT(res.getColumnCount() == this->getColumnCount(), "Invalid dimensions"); + STORM_LOG_ASSERT(this->getRowGroupCount() == res.getRowGroupCount(), "Invalid dimensions"); return res; } @@ -693,7 +727,7 @@ namespace storm { index_type subEntries = 0; for (index_type rowGroupIndex = 0, rowGroupIndexEnd = rowGroupToRowIndexMapping.size(); rowGroupIndex < rowGroupIndexEnd; ++rowGroupIndex) { // Determine which row we need to select from the current row group. - index_type rowToCopy = rowGroupIndices[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex]; + index_type rowToCopy = this->getRowGroupIndices()[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex]; // Iterate through that row and count the number of slots we have to reserve for copying. bool foundDiagonalElement = false; @@ -709,12 +743,12 @@ namespace storm { } // Now create the matrix to be returned with the appropriate size. - SparseMatrixBuilder<ValueType> matrixBuilder(rowGroupIndices.size() - 1, columnCount, subEntries); + SparseMatrixBuilder<ValueType> matrixBuilder(rowGroupIndices.get().size() - 1, columnCount, subEntries); // Copy over the selected lines from the source matrix. for (index_type rowGroupIndex = 0, rowGroupIndexEnd = rowGroupToRowIndexMapping.size(); rowGroupIndex < rowGroupIndexEnd; ++rowGroupIndex) { // Determine which row we need to select from the current row group. - index_type rowToCopy = rowGroupIndices[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex]; + index_type rowToCopy = this->getRowGroupIndices()[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex]; // Iterate through that row and copy the entries. This also inserts a zero element on the diagonal if // there is no entry yet. @@ -781,12 +815,7 @@ namespace storm { } } - std::vector<index_type> rowGroupIndices(rowCount + 1); - for (index_type i = 0; i <= rowCount; ++i) { - rowGroupIndices[i] = i; - } - - storm::storage::SparseMatrix<ValueType> transposedMatrix(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), false); + storm::storage::SparseMatrix<ValueType> transposedMatrix(columnCount, std::move(rowIndications), std::move(columnsAndValues), boost::none); return transposedMatrix; } @@ -1056,30 +1085,46 @@ namespace storm { template<typename ValueType> typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRow(index_type rowGroup, index_type offset) const { - assert(rowGroup < this->getRowGroupCount()); - assert(offset < this->getRowGroupEntryCount(rowGroup)); - return getRow(rowGroupIndices[rowGroup] + offset); + STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds."); + STORM_LOG_ASSERT(offset < this->getRowGroupEntryCount(rowGroup), "Row offset in row-group is out-of-bounds."); + if (!this->hasTrivialRowGrouping()) { + return getRow(this->getRowGroupIndices()[rowGroup] + offset); + } else { + return getRow(this->getRowGroupIndices()[rowGroup] + offset); + } } template<typename ValueType> typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRow(index_type rowGroup, index_type offset) { - assert(rowGroup < this->getRowGroupCount()); - assert(offset < this->getRowGroupEntryCount(rowGroup)); - return getRow(rowGroupIndices[rowGroup] + offset); + STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds."); + STORM_LOG_ASSERT(offset < this->getRowGroupEntryCount(rowGroup), "Row offset in row-group is out-of-bounds."); + if (!this->hasTrivialRowGrouping()) { + return getRow(this->getRowGroupIndices()[rowGroup] + offset); + } else { + return getRow(rowGroup + offset); + } } template<typename ValueType> typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRowGroup(index_type rowGroup) const { - assert(rowGroup < this->getRowGroupCount()); - return getRows(rowGroupIndices[rowGroup], rowGroupIndices[rowGroup + 1] - 1); + STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds."); + if (!this->hasTrivialRowGrouping()) { + return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1] - 1); + } else { + return getRows(rowGroup, rowGroup + 1); + } } template<typename ValueType> typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRowGroup(index_type rowGroup) { - assert(rowGroup < this->getRowGroupCount()); - return getRows(rowGroupIndices[rowGroup], rowGroupIndices[rowGroup + 1] - 1); + STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds."); + if (!this->hasTrivialRowGrouping()) { + return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1] - 1); + } else { + return getRows(rowGroup, rowGroup + 1); + } } template<typename ValueType> @@ -1113,8 +1158,8 @@ namespace storm { } template<typename ValueType> - bool SparseMatrix<ValueType>::hasNontrivialRowGrouping() const { - return nontrivialRowGrouping; + bool SparseMatrix<ValueType>::hasTrivialRowGrouping() const { + return trivialRowGrouping; } template<typename ValueType> @@ -1143,6 +1188,9 @@ namespace storm { // Check for matching sizes. if (this->getRowCount() != matrix.getRowCount()) return false; if (this->getColumnCount() != matrix.getColumnCount()) return false; + if (this->hasTrivialRowGrouping() && !matrix.hasTrivialRowGrouping()) return false; + if (!this->hasTrivialRowGrouping() && matrix.hasTrivialRowGrouping()) return false; + if (!this->hasTrivialRowGrouping() && !matrix.hasTrivialRowGrouping() && this->getRowGroupIndices() != matrix.getRowGroupIndices()) return false; if (this->getRowGroupIndices() != matrix.getRowGroupIndices()) return false; // Check the subset property for all rows individually. @@ -1174,7 +1222,7 @@ namespace storm { // Iterate over all row groups. for (typename SparseMatrix<ValueType>::index_type group = 0; group < matrix.getRowGroupCount(); ++group) { out << "\t---- group " << group << "/" << (matrix.getRowGroupCount() - 1) << " ---- " << std::endl; - for (typename SparseMatrix<ValueType>::index_type i = matrix.getRowGroupIndices()[group]; i < matrix.getRowGroupIndices()[group + 1]; ++i) { + for (typename SparseMatrix<ValueType>::index_type i = matrix.hasTrivialRowGrouping() ? group : matrix.getRowGroupIndices()[group]; i < matrix.hasTrivialRowGrouping() ? group + 1 : matrix.getRowGroupIndices()[group + 1]; ++i) { typename SparseMatrix<ValueType>::index_type nextIndex = matrix.rowIndications[i]; // Print the actual row. @@ -1237,7 +1285,9 @@ namespace storm { boost::hash_combine(result, this->getEntryCount()); boost::hash_combine(result, boost::hash_range(columnsAndValues.begin(), columnsAndValues.end())); boost::hash_combine(result, boost::hash_range(rowIndications.begin(), rowIndications.end())); - boost::hash_combine(result, boost::hash_range(rowGroupIndices.begin(), rowGroupIndices.end())); + if (!this->hasTrivialRowGrouping()) { + boost::hash_combine(result, boost::hash_range(rowGroupIndices.get().begin(), rowGroupIndices.get().end())); + } return result; } diff --git a/src/storage/SparseMatrix.h b/src/storage/SparseMatrix.h index 1ecee566f..730e018f2 100644 --- a/src/storage/SparseMatrix.h +++ b/src/storage/SparseMatrix.h @@ -7,9 +7,11 @@ #include <vector> #include <iterator> +#include <boost/functional/hash.hpp> +#include <boost/optional.hpp> + #include "src/utility/OsDetection.h" #include "src/adapters/CarlAdapter.h" -#include <boost/functional/hash.hpp> // Forward declaration for adapter classes. namespace storm { @@ -259,7 +261,8 @@ namespace storm { // The number of row groups in the matrix. index_type initialRowGroupCount; - std::vector<index_type> rowGroupIndices; + // The vector that stores the row-group indices (if they are non-trivial). + boost::optional<std::vector<index_type>> rowGroupIndices; // The storage for the columns and values of all entries in the matrix. std::vector<MatrixEntry<index_type, value_type>> columnsAndValues; @@ -447,9 +450,8 @@ namespace storm { * @param rowIndications The row indications vector of the matrix to be constructed. * @param columnsAndValues The vector containing the columns and values of the entries in the matrix. * @param rowGroupIndices The vector representing the row groups in the matrix. - * @param hasNontrivialRowGrouping If set to true, this indicates that the row grouping is non-trivial. */ - SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, value_type>> const& columnsAndValues, std::vector<index_type> const& rowGroupIndices, bool hasNontrivialRowGrouping); + SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, value_type>> const& columnsAndValues, boost::optional<std::vector<index_type>> const& rowGroupIndices); /*! * Constructs a sparse matrix by moving the given contents. @@ -458,9 +460,8 @@ namespace storm { * @param rowIndications The row indications vector of the matrix to be constructed. * @param columnsAndValues The vector containing the columns and values of the entries in the matrix. * @param rowGroupIndices The vector representing the row groups in the matrix. - * @param hasNontrivialRowGrouping If set to true, this indicates that the row grouping is non-trivial. */ - SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, value_type>>&& columnsAndValues, std::vector<index_type>&& rowGroupIndices, bool hasNontrivialRowGrouping); + SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, value_type>>&& columnsAndValues, boost::optional<std::vector<index_type>>&& rowGroupIndices); /*! * Assigns the contents of the given matrix to the current one by deep-copying its contents. @@ -913,27 +914,28 @@ namespace storm { iterator end(); /*! - * Retrieves whether the matrix has a (possibly) non-trivial row grouping. + * Retrieves whether the matrix has a trivial row grouping. * - * @return True iff the matrix has a (possibly) non-trivial row grouping. + * @return True iff the matrix has a trivial row grouping. */ - bool hasNontrivialRowGrouping() const; + bool hasTrivialRowGrouping() const; /*! * Returns a copy of the matrix with the chosen internal data type */ template<typename NewValueType> SparseMatrix<NewValueType> toValueType() const { - std::vector<MatrixEntry<SparseMatrix::index_type, NewValueType>> new_columnsAndValues; - std::vector<SparseMatrix::index_type> new_rowIndications(rowIndications); - std::vector<SparseMatrix::index_type> new_rowGroupIndices(rowGroupIndices); + std::vector<MatrixEntry<SparseMatrix::index_type, NewValueType>> newColumnsAndValues; + std::vector<SparseMatrix::index_type> newRowIndications(rowIndications); + boost::optional<std::vector<SparseMatrix::index_type>> newRowGroupIndices(rowGroupIndices); - new_columnsAndValues.resize(columnsAndValues.size()); - for (size_t i = 0, size = columnsAndValues.size(); i < size; ++i) { - new_columnsAndValues.at(i) = MatrixEntry<SparseMatrix::index_type, NewValueType>(columnsAndValues.at(i).getColumn(), static_cast<NewValueType>(columnsAndValues.at(i).getValue())); - } + newColumnsAndValues.resize(columnsAndValues.size()); + std::transform(columnsAndValues.begin(), columnsAndValues.end(), newColumnsAndValues.begin(), + [] (MatrixEntry<SparseMatrix::index_type, ValueType> const& a) { + return MatrixEntry<SparseMatrix::index_type, NewValueType>(a.getColumn(), static_cast<NewValueType>(a.getValue())); + }); - return SparseMatrix<NewValueType>(columnCount, std::move(new_rowIndications), std::move(new_columnsAndValues), std::move(new_rowGroupIndices), nontrivialRowGrouping); + return SparseMatrix<NewValueType>(columnCount, std::move(newRowIndications), std::move(newColumnsAndValues), std::move(newRowGroupIndices)); } private: @@ -972,12 +974,12 @@ namespace storm { // entry is not included anymore. std::vector<index_type> rowIndications; - // A flag that indicates whether the matrix has a non-trivial row-grouping, i.e. (possibly) more than one - // row per row group. - bool nontrivialRowGrouping; + // A flag indicating whether the matrix has a trivial row grouping. Note that this may be true and yet + // there may be row group indices, because they were requested from the outside. + bool trivialRowGrouping; - // A vector indicating the row groups of the matrix. - std::vector<index_type> rowGroupIndices; + // A vector indicating the row groups of the matrix. This needs to be mutible in case we create it on-the-fly. + mutable boost::optional<std::vector<index_type>> rowGroupIndices; }; From f285858e2819ce6497de8362e4d37138d7eba908 Mon Sep 17 00:00:00 2001 From: TimQu <tim.quatmann@rwth-aachen.de> Date: Mon, 7 Mar 2016 20:30:12 +0100 Subject: [PATCH 15/33] added required includes Former-commit-id: c523950b43c43d91ae19f3258683c53b7e19f650 --- src/settings/Option.cpp | 3 ++- src/solver/AbstractEquationSolver.h | 3 ++- src/storage/BitVectorHashMap.cpp | 1 + src/storage/dd/Bdd.cpp | 4 +++- src/utility/macros.h | 4 +++- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/settings/Option.cpp b/src/settings/Option.cpp index b5cba7759..cba074b58 100644 --- a/src/settings/Option.cpp +++ b/src/settings/Option.cpp @@ -2,6 +2,7 @@ #include <iomanip> #include <string> +#include <algorithm> #include "ArgumentBase.h" #include "Argument.h" @@ -211,4 +212,4 @@ namespace storm { return out; } } -} \ No newline at end of file +} diff --git a/src/solver/AbstractEquationSolver.h b/src/solver/AbstractEquationSolver.h index 904e459bd..a8f94dc69 100644 --- a/src/solver/AbstractEquationSolver.h +++ b/src/solver/AbstractEquationSolver.h @@ -1,6 +1,7 @@ #ifndef STORM_SOLVER_ABSTRACTEQUATIONSOLVER_H_ #define STORM_SOLVER_ABSTRACTEQUATIONSOLVER_H_ +#include <memory> #include "src/solver/TerminationCondition.h" namespace storm { @@ -50,4 +51,4 @@ namespace storm { } } -#endif /* STORM_SOLVER_ABSTRACTEQUATIONSOLVER_H_ */ \ No newline at end of file +#endif /* STORM_SOLVER_ABSTRACTEQUATIONSOLVER_H_ */ diff --git a/src/storage/BitVectorHashMap.cpp b/src/storage/BitVectorHashMap.cpp index c184b764b..328e601c4 100644 --- a/src/storage/BitVectorHashMap.cpp +++ b/src/storage/BitVectorHashMap.cpp @@ -1,5 +1,6 @@ #include "src/storage/BitVectorHashMap.h" +#include <algorithm> #include <iostream> #include "src/utility/macros.h" diff --git a/src/storage/dd/Bdd.cpp b/src/storage/dd/Bdd.cpp index 8f176048e..f8bf6b368 100644 --- a/src/storage/dd/Bdd.cpp +++ b/src/storage/dd/Bdd.cpp @@ -1,3 +1,5 @@ +#include <algorithm> + #include "src/storage/dd/Bdd.h" #include "src/storage/dd/Add.h" #include "src/storage/dd/Odd.h" @@ -360,4 +362,4 @@ namespace storm { template Add<DdType::Sylvan, double> Bdd<DdType::Sylvan>::ite(Add<DdType::Sylvan, double> const& thenAdd, Add<DdType::Sylvan, double> const& elseAdd) const; template Add<DdType::Sylvan, uint_fast64_t> Bdd<DdType::Sylvan>::ite(Add<DdType::Sylvan, uint_fast64_t> const& thenAdd, Add<DdType::Sylvan, uint_fast64_t> const& elseAdd) const; } -} \ No newline at end of file +} diff --git a/src/utility/macros.h b/src/utility/macros.h index 4f70b1691..8d7048fdb 100644 --- a/src/utility/macros.h +++ b/src/utility/macros.h @@ -2,6 +2,8 @@ #define STORM_UTILITY_MACROS_H_ #include <cassert> +#include <string.h> + #include "storm-config.h" #ifndef STORM_LOGGING_FRAMEWORK @@ -272,4 +274,4 @@ LOG4CPLUS_INFO(logger, "Enabled trace mode, log output gets printed to console." STORM_PRINT(message); \ } -#endif /* STORM_UTILITY_MACROS_H_ */ \ No newline at end of file +#endif /* STORM_UTILITY_MACROS_H_ */ From 0b98412bb43bf998c2397e3e6add2f88ac340e35 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 7 Mar 2016 22:45:42 +0100 Subject: [PATCH 16/33] further work on making row-grouping optional Former-commit-id: bae568660f238424524b14694d39929165801aa5 --- src/storage/SparseMatrix.cpp | 14 ++++++++------ src/storage/dd/Add.cpp | 6 +++--- test/functional/storage/SparseMatrixTest.cpp | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp index 83bc7dc83..df78e4e2d 100644 --- a/src/storage/SparseMatrix.cpp +++ b/src/storage/SparseMatrix.cpp @@ -80,15 +80,17 @@ namespace storm { if (initialEntryCountSet) { columnsAndValues.reserve(initialEntryCount); } - if (initialRowGroupCountSet && hasCustomRowGrouping) { + if (hasCustomRowGrouping) { rowGroupIndices = std::vector<index_type>(); + } + if (initialRowGroupCountSet && hasCustomRowGrouping) { rowGroupIndices.get().reserve(initialRowGroupCount + 1); } rowIndications.push_back(0); } template<typename ValueType> - SparseMatrixBuilder<ValueType>::SparseMatrixBuilder(SparseMatrix<ValueType>&& matrix) : initialRowCountSet(false), initialRowCount(0), initialColumnCountSet(false), initialColumnCount(0), initialEntryCountSet(false), initialEntryCount(0), forceInitialDimensions(false), hasCustomRowGrouping(matrix.nontrivialRowGrouping), initialRowGroupCountSet(false), initialRowGroupCount(0), rowGroupIndices(), columnsAndValues(std::move(matrix.columnsAndValues)), rowIndications(std::move(matrix.rowIndications)), currentEntryCount(matrix.entryCount), lastRow(matrix.rowCount - 1), lastColumn(columnsAndValues.back().getColumn()), highestColumn(matrix.getColumnCount() - 1), currentRowGroup() { + SparseMatrixBuilder<ValueType>::SparseMatrixBuilder(SparseMatrix<ValueType>&& matrix) : initialRowCountSet(false), initialRowCount(0), initialColumnCountSet(false), initialColumnCount(0), initialEntryCountSet(false), initialEntryCount(0), forceInitialDimensions(false), hasCustomRowGrouping(!matrix.trivialRowGrouping), initialRowGroupCountSet(false), initialRowGroupCount(0), rowGroupIndices(), columnsAndValues(std::move(matrix.columnsAndValues)), rowIndications(std::move(matrix.rowIndications)), currentEntryCount(matrix.entryCount), lastRow(matrix.rowCount - 1), lastColumn(columnsAndValues.back().getColumn()), highestColumn(matrix.getColumnCount() - 1), currentRowGroup() { // If the matrix has a custom row grouping, we move it and remove the last element to make it 'open' again. if (hasCustomRowGrouping) { @@ -200,7 +202,7 @@ namespace storm { } } - return SparseMatrix<ValueType>(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), hasCustomRowGrouping); + return SparseMatrix<ValueType>(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)); } template<typename ValueType> @@ -297,7 +299,7 @@ namespace storm { } template<typename ValueType> - SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType> const& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), rowGroupIndices(other.rowGroupIndices) { + SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType> const& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), trivialRowGrouping(other.trivialRowGrouping), rowGroupIndices(other.rowGroupIndices) { // Intentionally left empty. } @@ -309,7 +311,7 @@ namespace storm { } template<typename ValueType> - SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType>&& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), rowGroupIndices(std::move(other.rowGroupIndices)) { + SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType>&& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), trivialRowGrouping(other.trivialRowGrouping), rowGroupIndices(std::move(other.rowGroupIndices)) { // Now update the source matrix other.rowCount = 0; other.columnCount = 0; @@ -322,7 +324,7 @@ namespace storm { } template<typename ValueType> - SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, ValueType>>&& columnsAndValues, boost::optional<std::vector<index_type>>&& rowGroupIndices, bool nontrivialRowGrouping) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), trivialRowGrouping(!rowGroupIndices), rowGroupIndices(std::move(rowGroupIndices)) { + SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, ValueType>>&& columnsAndValues, boost::optional<std::vector<index_type>>&& rowGroupIndices) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), trivialRowGrouping(!rowGroupIndices), rowGroupIndices(std::move(rowGroupIndices)) { this->updateNonzeroEntryCount(); } diff --git a/src/storage/dd/Add.cpp b/src/storage/dd/Add.cpp index ecd98c2d9..40223da75 100644 --- a/src/storage/dd/Add.cpp +++ b/src/storage/dd/Add.cpp @@ -459,7 +459,7 @@ namespace storm { rowIndications[0] = 0; // Construct matrix and return result. - return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(trivialRowGroupIndices), false); + return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), boost::none); } template<DdType LibraryType, typename ValueType> @@ -583,7 +583,7 @@ namespace storm { } rowIndications[0] = 0; - return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), true); + return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)); } template<DdType LibraryType, typename ValueType> @@ -708,7 +708,7 @@ namespace storm { } rowIndications[0] = 0; - return std::make_pair(storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), true), std::move(explicitVector)); + return std::make_pair(storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)), std::move(explicitVector)); } template<DdType LibraryType, typename ValueType> diff --git a/test/functional/storage/SparseMatrixTest.cpp b/test/functional/storage/SparseMatrixTest.cpp index 1fe0041f7..321fc7b91 100644 --- a/test/functional/storage/SparseMatrixTest.cpp +++ b/test/functional/storage/SparseMatrixTest.cpp @@ -155,8 +155,8 @@ TEST(SparseMatrix, CreationWithMovingContents) { columnsAndValues.emplace_back(1, 0.7); columnsAndValues.emplace_back(3, 0.2); - ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, {0, 1, 2, 3}, false)); - storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, {0, 1, 2, 3}, false); + ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, boost::optional<std::vector<uint_fast64_t>>({0, 1, 2, 3}))); + storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, boost::optional<std::vector<uint_fast64_t>>({0, 1, 2, 3})); ASSERT_EQ(3ul, matrix.getRowCount()); ASSERT_EQ(4ul, matrix.getColumnCount()); ASSERT_EQ(5ul, matrix.getEntryCount()); From a40d12f9153bd8e0c0917120b8966819db20791c Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 8 Mar 2016 08:48:41 +0100 Subject: [PATCH 17/33] made getRowGroup more consistent and fixed some introduced bugs Former-commit-id: 99b6c0e3a5b5d263c185fbd4bdb08d435c5b688b --- src/storage/SparseMatrix.cpp | 14 +++++++------- src/storage/SparseMatrix.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp index df78e4e2d..99e21ee0d 100644 --- a/src/storage/SparseMatrix.cpp +++ b/src/storage/SparseMatrix.cpp @@ -1067,22 +1067,22 @@ namespace storm { template<typename ValueType> typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRows(index_type startRow, index_type endRow) const { - return const_rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow + 1] - this->rowIndications[startRow]); + return const_rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow] - this->rowIndications[startRow]); } template<typename ValueType> typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRows(index_type startRow, index_type endRow) { - return rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow + 1] - this->rowIndications[startRow]); + return rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow] - this->rowIndications[startRow]); } template<typename ValueType> typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRow(index_type row) const { - return getRows(row, row); + return getRows(row, row + 1); } template<typename ValueType> typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRow(index_type row) { - return getRows(row, row); + return getRows(row, row + 1); } template<typename ValueType> @@ -1096,7 +1096,6 @@ namespace storm { } } - template<typename ValueType> typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRow(index_type rowGroup, index_type offset) { STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds."); @@ -1104,6 +1103,7 @@ namespace storm { if (!this->hasTrivialRowGrouping()) { return getRow(this->getRowGroupIndices()[rowGroup] + offset); } else { + STORM_LOG_ASSERT(offset == 0, "Invalid offset."); return getRow(rowGroup + offset); } } @@ -1113,7 +1113,7 @@ namespace storm { typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRowGroup(index_type rowGroup) const { STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds."); if (!this->hasTrivialRowGrouping()) { - return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1] - 1); + return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1]); } else { return getRows(rowGroup, rowGroup + 1); } @@ -1123,7 +1123,7 @@ namespace storm { typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRowGroup(index_type rowGroup) { STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds."); if (!this->hasTrivialRowGrouping()) { - return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1] - 1); + return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1]); } else { return getRows(rowGroup, rowGroup + 1); } diff --git a/src/storage/SparseMatrix.h b/src/storage/SparseMatrix.h index 730e018f2..c5c7133c6 100644 --- a/src/storage/SparseMatrix.h +++ b/src/storage/SparseMatrix.h @@ -805,7 +805,7 @@ namespace storm { * Returns an object representing the consecutive rows given by the parameters. * * @param startRow The starting row. - * @param endRow The ending row (which is included in the result). + * @param endRow The ending row (which is *not* included in the result). * @return An object representing the consecutive rows given by the parameters. */ const_rows getRows(index_type startRow, index_type endRow) const; @@ -814,7 +814,7 @@ namespace storm { * Returns an object representing the consecutive rows given by the parameters. * * @param startRow The starting row. - * @param endRow The ending row (which is included in the result). + * @param endRow The ending row (which is *not* included in the result). * @return An object representing the consecutive rows given by the parameters. */ rows getRows(index_type startRow, index_type endRow); From f54c2fb8e7dc20df6024c853e11cd1ea3ee4a5c7 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 8 Mar 2016 10:00:17 +0100 Subject: [PATCH 18/33] tests passing again Former-commit-id: 8e3311f4c7afd7dfc456e22ad7998b929aee76ed --- src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp | 2 +- src/storage/SparseMatrix.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index 5043c8296..a4724da46 100644 --- a/src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -354,7 +354,7 @@ namespace storm { STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive."); storm::storage::SparseMatrix<ValueType> uniformizedMatrix = computeUniformizedMatrix(rateMatrix, storm::storage::BitVector(numberOfStates, true), uniformizationRate, exitRateVector); - + // Compute the total state reward vector. std::vector<ValueType> totalRewardVector = rewardModel.getTotalRewardVector(rateMatrix, exitRateVector); diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp index 99e21ee0d..9795dbe2d 100644 --- a/src/storage/SparseMatrix.cpp +++ b/src/storage/SparseMatrix.cpp @@ -498,7 +498,7 @@ namespace storm { if (!this->rowGroupIndices) { STORM_LOG_ASSERT(trivialRowGrouping, "Only trivial row-groupings can be constructed on-the-fly."); this->rowGroupIndices = std::vector<index_type>(this->getRowCount() + 1); - for (uint_fast64_t group = 0; group < this->getRowCount(); ++group) { + for (uint_fast64_t group = 0; group <= this->getRowCount(); ++group) { this->rowGroupIndices.get()[group] = group; } } @@ -1224,7 +1224,10 @@ namespace storm { // Iterate over all row groups. for (typename SparseMatrix<ValueType>::index_type group = 0; group < matrix.getRowGroupCount(); ++group) { out << "\t---- group " << group << "/" << (matrix.getRowGroupCount() - 1) << " ---- " << std::endl; - for (typename SparseMatrix<ValueType>::index_type i = matrix.hasTrivialRowGrouping() ? group : matrix.getRowGroupIndices()[group]; i < matrix.hasTrivialRowGrouping() ? group + 1 : matrix.getRowGroupIndices()[group + 1]; ++i) { + typename SparseMatrix<ValueType>::index_type start = matrix.hasTrivialRowGrouping() ? group : matrix.getRowGroupIndices()[group]; + typename SparseMatrix<ValueType>::index_type end = matrix.hasTrivialRowGrouping() ? group + 1 : matrix.getRowGroupIndices()[group + 1]; + + for (typename SparseMatrix<ValueType>::index_type i = start; i < end; ++i) { typename SparseMatrix<ValueType>::index_type nextIndex = matrix.rowIndications[i]; // Print the actual row. From 45e59848a9711e54e72e148de5a03ca340bac17d Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 8 Mar 2016 17:01:17 +0100 Subject: [PATCH 19/33] first steps Former-commit-id: 12d930813b1b2856104f9ac32f1b9b1af09a251e --- src/logic/EventuallyFormula.cpp | 8 ++- src/logic/EventuallyFormula.h | 3 +- src/logic/ExpectedTimeOperatorFormula.cpp | 25 +++------ src/logic/ExpectedTimeOperatorFormula.h | 6 +-- src/logic/Formula.cpp | 22 +++++++- src/logic/Formula.h | 11 +++- src/logic/FragmentChecker.cpp | 10 ++-- src/logic/FragmentSpecification.cpp | 22 +++++--- src/logic/FragmentSpecification.h | 10 ++-- src/logic/LongRunAverageOperatorFormula.cpp | 25 +++------ src/logic/LongRunAverageOperatorFormula.h | 6 +-- src/logic/OperatorFormula.cpp | 44 +++++++++++---- src/logic/OperatorFormula.h | 26 +++++++-- src/logic/ProbabilityOperatorFormula.cpp | 25 +++------ src/logic/ProbabilityOperatorFormula.h | 6 +-- src/logic/RewardOperatorFormula.cpp | 25 +++------ src/logic/RewardOperatorFormula.h | 6 +-- src/modelchecker/AbstractModelChecker.cpp | 10 ++-- src/modelchecker/AbstractModelChecker.h | 2 +- src/parser/FormulaParser.cpp | 60 +++++++++++++-------- 20 files changed, 194 insertions(+), 158 deletions(-) diff --git a/src/logic/EventuallyFormula.cpp b/src/logic/EventuallyFormula.cpp index 71ff4ac54..67699cfb9 100644 --- a/src/logic/EventuallyFormula.cpp +++ b/src/logic/EventuallyFormula.cpp @@ -11,6 +11,10 @@ namespace storm { } bool EventuallyFormula::isEventuallyFormula() const { + return true; + } + + bool EventuallyFormula::isReachabilityProbabilityFormula() const { return context == FormulaContext::Probability; } @@ -18,7 +22,7 @@ namespace storm { return context == FormulaContext::Reward; } - bool EventuallyFormula::isReachbilityExpectedTimeFormula() const { + bool EventuallyFormula::isReachabilityExpectedTimeFormula() const { return context == FormulaContext::ExpectedTime; } @@ -31,7 +35,7 @@ namespace storm { } bool EventuallyFormula::isExpectedTimePathFormula() const { - return this->isReachbilityExpectedTimeFormula(); + return this->isReachabilityExpectedTimeFormula(); } boost::any EventuallyFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const { diff --git a/src/logic/EventuallyFormula.h b/src/logic/EventuallyFormula.h index 5a0070a16..5cca412a9 100644 --- a/src/logic/EventuallyFormula.h +++ b/src/logic/EventuallyFormula.h @@ -15,8 +15,9 @@ namespace storm { } virtual bool isEventuallyFormula() const override; + virtual bool isReachabilityProbabilityFormula() const override; virtual bool isReachabilityRewardFormula() const override; - virtual bool isReachbilityExpectedTimeFormula() const override; + virtual bool isReachabilityExpectedTimeFormula() const override; virtual bool isProbabilityPathFormula() const override; virtual bool isRewardPathFormula() const override; virtual bool isExpectedTimePathFormula() const override; diff --git a/src/logic/ExpectedTimeOperatorFormula.cpp b/src/logic/ExpectedTimeOperatorFormula.cpp index 5dc8161ae..fb61b8bbd 100644 --- a/src/logic/ExpectedTimeOperatorFormula.cpp +++ b/src/logic/ExpectedTimeOperatorFormula.cpp @@ -2,22 +2,13 @@ #include "src/logic/FormulaVisitor.h" +#include "src/utility/macros.h" +#include "src/exceptions/InvalidPropertyException.h" + namespace storm { namespace logic { - ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(std::shared_ptr<Formula const> const& subformula) : ExpectedTimeOperatorFormula(boost::none, boost::none, subformula) { - // Intentionally left empty. - } - - ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : ExpectedTimeOperatorFormula(boost::none, bound, subformula) { - // Intentionally left empty. - } - - ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : ExpectedTimeOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), bound, subformula) { - // Intentionally left empty. - } - - ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula) : ExpectedTimeOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), boost::none, subformula) { - // Intentionally left empty. + ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation) { + STORM_LOG_THROW(this->getMeasureType() == MeasureType::Expectation || this->getMeasureType() == MeasureType::Variance, storm::exceptions::InvalidPropertyException, "Invalid measure type in ET-operator."); } bool ExpectedTimeOperatorFormula::isExpectedTimeOperatorFormula() const { @@ -28,12 +19,8 @@ namespace storm { return visitor.visit(*this, data); } - ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula) : OperatorFormula(optimalityType, bound, subformula) { - // Intentionally left empty. - } - std::shared_ptr<Formula> ExpectedTimeOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const { - return std::make_shared<ExpectedTimeOperatorFormula>(this->optimalityType, this->bound, this->getSubformula().substitute(substitution)); + return std::make_shared<ExpectedTimeOperatorFormula>(this->getSubformula().substitute(substitution), this->operatorInformation); } std::ostream& ExpectedTimeOperatorFormula::writeToStream(std::ostream& out) const { diff --git a/src/logic/ExpectedTimeOperatorFormula.h b/src/logic/ExpectedTimeOperatorFormula.h index 5e1925b44..a6e7d3fbd 100644 --- a/src/logic/ExpectedTimeOperatorFormula.h +++ b/src/logic/ExpectedTimeOperatorFormula.h @@ -9,11 +9,7 @@ namespace storm { namespace logic { class ExpectedTimeOperatorFormula : public OperatorFormula { public: - ExpectedTimeOperatorFormula(std::shared_ptr<Formula const> const& subformula); - ExpectedTimeOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula); - ExpectedTimeOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula); - ExpectedTimeOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula); - ExpectedTimeOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula); + ExpectedTimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation()); virtual ~ExpectedTimeOperatorFormula() { // Intentionally left empty. diff --git a/src/logic/Formula.cpp b/src/logic/Formula.cpp index 6c7084f53..3a14b7db8 100644 --- a/src/logic/Formula.cpp +++ b/src/logic/Formula.cpp @@ -62,6 +62,10 @@ namespace storm { return false; } + bool Formula::isReachabilityProbabilityFormula() const { + return false; + } + bool Formula::isGloballyFormula() const { return false; } @@ -122,7 +126,7 @@ namespace storm { return false; } - bool Formula::isReachbilityExpectedTimeFormula() const { + bool Formula::isReachabilityExpectedTimeFormula() const { return false; } @@ -264,6 +268,22 @@ namespace storm { return dynamic_cast<EventuallyFormula const&>(*this); } + EventuallyFormula& Formula::asReachabilityProbabilityFormula() { + return dynamic_cast<EventuallyFormula&>(*this); + } + + EventuallyFormula const& Formula::asReachabilityProbabilityFormula() const { + return dynamic_cast<EventuallyFormula const&>(*this); + } + + EventuallyFormula& Formula::asReachabilityExpectedTimeFormula() { + return dynamic_cast<EventuallyFormula&>(*this); + } + + EventuallyFormula const& Formula::asReachabilityExpectedTimeFormula() const { + return dynamic_cast<EventuallyFormula const&>(*this); + } + GloballyFormula& Formula::asGloballyFormula() { return dynamic_cast<GloballyFormula&>(*this); } diff --git a/src/logic/Formula.h b/src/logic/Formula.h index 7d77de7b3..f7916f400 100644 --- a/src/logic/Formula.h +++ b/src/logic/Formula.h @@ -65,8 +65,9 @@ namespace storm { virtual bool isNextFormula() const; virtual bool isUntilFormula() const; virtual bool isBoundedUntilFormula() const; - virtual bool isEventuallyFormula() const; virtual bool isGloballyFormula() const; + virtual bool isEventuallyFormula() const; + virtual bool isReachabilityProbabilityFormula() const; // Reward formulas. virtual bool isCumulativeRewardFormula() const; @@ -75,7 +76,7 @@ namespace storm { virtual bool isLongRunAverageRewardFormula() const; // Expected time formulas. - virtual bool isReachbilityExpectedTimeFormula() const; + virtual bool isReachabilityExpectedTimeFormula() const; // Type checks for abstract intermediate classes. virtual bool isBinaryPathFormula() const; @@ -126,8 +127,14 @@ namespace storm { EventuallyFormula& asEventuallyFormula(); EventuallyFormula const& asEventuallyFormula() const; + EventuallyFormula& asReachabilityProbabilityFormula(); + EventuallyFormula const& asReachabilityProbabilityFormula() const; + EventuallyFormula& asReachabilityRewardFormula(); EventuallyFormula const& asReachabilityRewardFormula() const; + + EventuallyFormula& asReachabilityExpectedTimeFormula(); + EventuallyFormula const& asReachabilityExpectedTimeFormula() const; GloballyFormula& asGloballyFormula(); GloballyFormula const& asGloballyFormula() const; diff --git a/src/logic/FragmentChecker.cpp b/src/logic/FragmentChecker.cpp index 6bf03ddb7..fb400fc5b 100644 --- a/src/logic/FragmentChecker.cpp +++ b/src/logic/FragmentChecker.cpp @@ -73,7 +73,7 @@ namespace storm { } if (inherited.getSpecification().areOnlyEventuallyFormuluasInConditionalFormulasAllowed()) { if (f.isConditionalProbabilityFormula()) { - result = result && f.getSubformula().isEventuallyFormula() && f.getConditionFormula().isEventuallyFormula(); + result = result && f.getSubformula().isReachabilityProbabilityFormula() && f.getConditionFormula().isReachabilityProbabilityFormula(); } else if (f.isConditionalRewardFormula()) { result = result && f.getSubformula().isReachabilityRewardFormula() && f.getConditionFormula().isEventuallyFormula(); } @@ -91,15 +91,15 @@ namespace storm { boost::any FragmentChecker::visit(EventuallyFormula const& f, boost::any const& data) const { InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data); bool result = true; - if (f.isEventuallyFormula()) { - result = inherited.getSpecification().areEventuallyFormulasAllowed(); + if (f.isReachabilityProbabilityFormula()) { + result = inherited.getSpecification().areReachabilityProbabilityFormulasAllowed(); if (!inherited.getSpecification().areNestedPathFormulasAllowed()) { result = result && !f.getSubformula().isPathFormula(); } } else if (f.isReachabilityRewardFormula()) { result = result && inherited.getSpecification().areReachabilityRewardFormulasAllowed(); result = result && f.getSubformula().isStateFormula(); - } else if (f.isReachbilityExpectedTimeFormula()) { + } else if (f.isReachabilityExpectedTimeFormula()) { result = result && inherited.getSpecification().areReachbilityExpectedTimeFormulasAllowed(); result = result && f.getSubformula().isStateFormula(); } @@ -111,6 +111,7 @@ namespace storm { InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data); bool result = inherited.getSpecification().areExpectedTimeOperatorsAllowed(); result = result && f.getSubformula().isExpectedTimePathFormula(); + result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == MeasureType::Expectation); if (!inherited.getSpecification().areNestedOperatorsAllowed()) { result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false)))); } else { @@ -177,6 +178,7 @@ namespace storm { InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data); bool result = inherited.getSpecification().areRewardOperatorsAllowed(); result = result && (f.getSubformula().isRewardPathFormula() || f.getSubformula().isConditionalRewardFormula()); + result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == MeasureType::Expectation); if (!inherited.getSpecification().areNestedOperatorsAllowed()) { result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false)))); } else { diff --git a/src/logic/FragmentSpecification.cpp b/src/logic/FragmentSpecification.cpp index 378fe3a88..e243562e8 100644 --- a/src/logic/FragmentSpecification.cpp +++ b/src/logic/FragmentSpecification.cpp @@ -22,7 +22,7 @@ namespace storm { pctl.setProbabilityOperatorsAllowed(true); pctl.setGloballyFormulasAllowed(true); - pctl.setEventuallyFormulasAllowed(true); + pctl.setReachabilityProbabilityFormulasAllowed(true); pctl.setNextFormulasAllowed(true); pctl.setUntilFormulasAllowed(true); pctl.setBoundedUntilFormulasAllowed(true); @@ -70,7 +70,7 @@ namespace storm { longRunAverageOperator = false; globallyFormula = false; - eventuallyFormula = false; + reachabilityProbabilityFormula = false; nextFormula = false; untilFormula = false; boundedUntilFormula = false; @@ -96,6 +96,7 @@ namespace storm { onlyEventuallyFormuluasInConditionalFormulas = true; stepBoundedUntilFormulas = false; timeBoundedUntilFormulas = false; + varianceAsMeasureType = false; } FragmentSpecification FragmentSpecification::copy() const { @@ -147,12 +148,12 @@ namespace storm { return *this; } - bool FragmentSpecification::areEventuallyFormulasAllowed() const { - return eventuallyFormula; + bool FragmentSpecification::areReachabilityProbabilityFormulasAllowed() const { + return reachabilityProbabilityFormula; } - FragmentSpecification& FragmentSpecification::setEventuallyFormulasAllowed(bool newValue) { - this->eventuallyFormula = newValue; + FragmentSpecification& FragmentSpecification::setReachabilityProbabilityFormulasAllowed(bool newValue) { + this->reachabilityProbabilityFormula = newValue; return *this; } @@ -355,5 +356,14 @@ namespace storm { return *this; } + bool FragmentSpecification::isVarianceMeasureTypeAllowed() const { + return varianceAsMeasureType; + } + + FragmentSpecification& FragmentSpecification::setVarianceMeasureTypeAllowed(bool newValue) { + this->varianceAsMeasureType = newValue; + return *this; + } + } } \ No newline at end of file diff --git a/src/logic/FragmentSpecification.h b/src/logic/FragmentSpecification.h index 1bd46f4f7..e850fb172 100644 --- a/src/logic/FragmentSpecification.h +++ b/src/logic/FragmentSpecification.h @@ -28,8 +28,8 @@ namespace storm { bool areGloballyFormulasAllowed() const; FragmentSpecification& setGloballyFormulasAllowed(bool newValue); - bool areEventuallyFormulasAllowed() const; - FragmentSpecification& setEventuallyFormulasAllowed(bool newValue); + bool areReachabilityProbabilityFormulasAllowed() const; + FragmentSpecification& setReachabilityProbabilityFormulasAllowed(bool newValue); bool areNextFormulasAllowed() const; FragmentSpecification& setNextFormulasAllowed(bool newValue); @@ -91,6 +91,9 @@ namespace storm { bool areTimeBoundedUntilFormulasAllowed() const; FragmentSpecification& setTimeBoundedUntilFormulasAllowed(bool newValue); + bool isVarianceMeasureTypeAllowed() const; + FragmentSpecification& setVarianceMeasureTypeAllowed(bool newValue); + FragmentSpecification& setOperatorsAllowed(bool newValue); FragmentSpecification& setExpectedTimeAllowed(bool newValue); FragmentSpecification& setLongRunAverageProbabilitiesAllowed(bool newValue); @@ -103,7 +106,7 @@ namespace storm { bool longRunAverageOperator; bool globallyFormula; - bool eventuallyFormula; + bool reachabilityProbabilityFormula; bool nextFormula; bool untilFormula; bool boundedUntilFormula; @@ -130,6 +133,7 @@ namespace storm { bool onlyEventuallyFormuluasInConditionalFormulas; bool stepBoundedUntilFormulas; bool timeBoundedUntilFormulas; + bool varianceAsMeasureType; }; // Propositional. diff --git a/src/logic/LongRunAverageOperatorFormula.cpp b/src/logic/LongRunAverageOperatorFormula.cpp index c9d781905..fe261224c 100644 --- a/src/logic/LongRunAverageOperatorFormula.cpp +++ b/src/logic/LongRunAverageOperatorFormula.cpp @@ -2,24 +2,15 @@ #include "src/logic/FormulaVisitor.h" +#include "src/utility/macros.h" +#include "src/exceptions/InvalidPropertyException.h" + namespace storm { namespace logic { - LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(std::shared_ptr<Formula const> const& subformula) : LongRunAverageOperatorFormula(boost::none, boost::none, subformula) { - // Intentionally left empty. - } - - LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : LongRunAverageOperatorFormula(boost::none, bound, subformula) { - // Intentionally left empty. - } - - LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : LongRunAverageOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), bound, subformula) { - // Intentionally left empty. + LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation) { + STORM_LOG_THROW(this->getMeasureType() == MeasureType::Value, storm::exceptions::InvalidPropertyException, "Invalid measure type in LRA-operator."); } - LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula) : LongRunAverageOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), boost::none, subformula) { - // Intentionally left empty. - } - bool LongRunAverageOperatorFormula::isLongRunAverageOperatorFormula() const { return true; } @@ -28,12 +19,8 @@ namespace storm { return visitor.visit(*this, data); } - LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula) : OperatorFormula(optimalityType, bound, subformula) { - // Intentionally left empty. - } - std::shared_ptr<Formula> LongRunAverageOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const { - return std::make_shared<LongRunAverageOperatorFormula>(this->optimalityType, this->bound, this->getSubformula().substitute(substitution)); + return std::make_shared<LongRunAverageOperatorFormula>(this->getSubformula().substitute(substitution), this->operatorInformation); } std::ostream& LongRunAverageOperatorFormula::writeToStream(std::ostream& out) const { diff --git a/src/logic/LongRunAverageOperatorFormula.h b/src/logic/LongRunAverageOperatorFormula.h index d4a785b80..394188b67 100644 --- a/src/logic/LongRunAverageOperatorFormula.h +++ b/src/logic/LongRunAverageOperatorFormula.h @@ -7,11 +7,7 @@ namespace storm { namespace logic { class LongRunAverageOperatorFormula : public OperatorFormula { public: - LongRunAverageOperatorFormula(std::shared_ptr<Formula const> const& subformula); - LongRunAverageOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula); - LongRunAverageOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula); - LongRunAverageOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula); - LongRunAverageOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula); + LongRunAverageOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation()); virtual ~LongRunAverageOperatorFormula() { // Intentionally left empty. diff --git a/src/logic/OperatorFormula.cpp b/src/logic/OperatorFormula.cpp index a9cdc09ae..97690d7bf 100644 --- a/src/logic/OperatorFormula.cpp +++ b/src/logic/OperatorFormula.cpp @@ -2,44 +2,67 @@ namespace storm { namespace logic { - OperatorFormula::OperatorFormula(boost::optional<storm::solver::OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula) : UnaryStateFormula(subformula), bound(bound), optimalityType(optimalityType) { + std::ostream& operator<<(std::ostream& out, MeasureType const& type) { + switch (type) { + case MeasureType::Value: + out << "val"; + break; + case MeasureType::Expectation: + out << "exp"; + break; + case MeasureType::Variance: + out << "var"; + break; + } + return out; + } + + OperatorInformation::OperatorInformation(MeasureType const& measureType, boost::optional<storm::solver::OptimizationDirection> const& optimizationDirection, boost::optional<Bound<double>> const& bound) : measureType(measureType), optimalityType(optimizationDirection), bound(bound) { + // Intentionally left empty. + } + + OperatorFormula::OperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : UnaryStateFormula(subformula), operatorInformation(operatorInformation) { // Intentionally left empty. } bool OperatorFormula::hasBound() const { - return static_cast<bool>(bound); + return static_cast<bool>(operatorInformation.bound); } ComparisonType OperatorFormula::getComparisonType() const { - return bound.get().comparisonType; + return operatorInformation.bound.get().comparisonType; } void OperatorFormula::setComparisonType(ComparisonType newComparisonType) { - bound.get().comparisonType = newComparisonType; + operatorInformation.bound.get().comparisonType = newComparisonType; } double OperatorFormula::getThreshold() const { - return bound.get().threshold; + return operatorInformation.bound.get().threshold; } void OperatorFormula::setThreshold(double newThreshold) { - bound.get().threshold = newThreshold; + operatorInformation.bound.get().threshold = newThreshold; } Bound<double> const& OperatorFormula::getBound() const { - return bound.get(); + return operatorInformation.bound.get(); } void OperatorFormula::setBound(Bound<double> const& newBound) { - bound = newBound; + operatorInformation.bound = newBound; } bool OperatorFormula::hasOptimalityType() const { - return static_cast<bool>(optimalityType); + return static_cast<bool>(operatorInformation.optimalityType); } OptimizationDirection const& OperatorFormula::getOptimalityType() const { - return optimalityType.get(); + return operatorInformation.optimalityType.get(); + } + + MeasureType OperatorFormula::getMeasureType() const { + return operatorInformation.measureType; } bool OperatorFormula::isOperatorFormula() const { @@ -47,6 +70,7 @@ namespace storm { } std::ostream& OperatorFormula::writeToStream(std::ostream& out) const { + out << "[" << this->operatorInformation.measureType << "]"; if (hasOptimalityType()) { out << (getOptimalityType() == OptimizationDirection::Minimize ? "min" : "max"); } diff --git a/src/logic/OperatorFormula.h b/src/logic/OperatorFormula.h index 7660799a4..43c97ea45 100644 --- a/src/logic/OperatorFormula.h +++ b/src/logic/OperatorFormula.h @@ -9,14 +9,27 @@ namespace storm { namespace logic { + enum class MeasureType { Value, Expectation, Variance }; + + std::ostream& operator<<(std::ostream& out, MeasureType const& type); + + struct OperatorInformation { + OperatorInformation(MeasureType const& measureType = MeasureType::Value, boost::optional<storm::solver::OptimizationDirection> const& optimizationDirection = boost::none, boost::optional<Bound<double>> const& bound = boost::none); + + MeasureType measureType; + boost::optional<storm::solver::OptimizationDirection> optimalityType; + boost::optional<Bound<double>> bound; + }; + class OperatorFormula : public UnaryStateFormula { public: - OperatorFormula(boost::optional<storm::solver::OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula); + OperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation()); virtual ~OperatorFormula() { // Intentionally left empty. } - + + // Bound-related accessors. bool hasBound() const; ComparisonType getComparisonType() const; void setComparisonType(ComparisonType newComparisonType); @@ -24,16 +37,19 @@ namespace storm { void setThreshold(double newThreshold); Bound<double> const& getBound() const; void setBound(Bound<double> const& newBound); + + // Optimality-type-related accessors. bool hasOptimalityType() const; storm::solver::OptimizationDirection const& getOptimalityType() const; virtual bool isOperatorFormula() const override; + // Measure-type-related accessors. + MeasureType getMeasureType() const; + virtual std::ostream& writeToStream(std::ostream& out) const override; protected: - std::string operatorSymbol; - boost::optional<Bound<double>> bound; - boost::optional<storm::solver::OptimizationDirection> optimalityType; + OperatorInformation operatorInformation; }; } } diff --git a/src/logic/ProbabilityOperatorFormula.cpp b/src/logic/ProbabilityOperatorFormula.cpp index 09680cbc5..b3f7a303c 100644 --- a/src/logic/ProbabilityOperatorFormula.cpp +++ b/src/logic/ProbabilityOperatorFormula.cpp @@ -2,22 +2,13 @@ #include "src/logic/FormulaVisitor.h" +#include "src/utility/macros.h" +#include "src/exceptions/InvalidPropertyException.h" + namespace storm { namespace logic { - ProbabilityOperatorFormula::ProbabilityOperatorFormula(std::shared_ptr<Formula const> const& subformula) : ProbabilityOperatorFormula(boost::none, boost::none, subformula) { - // Intentionally left empty. - } - - ProbabilityOperatorFormula::ProbabilityOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : ProbabilityOperatorFormula(boost::none, bound, subformula) { - // Intentionally left empty. - } - - ProbabilityOperatorFormula::ProbabilityOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : ProbabilityOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), bound, subformula) { - // Intentionally left empty. - } - - ProbabilityOperatorFormula::ProbabilityOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula) : ProbabilityOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), boost::none, subformula) { - // Intentionally left empty. + ProbabilityOperatorFormula::ProbabilityOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation) { + STORM_LOG_THROW(this->getMeasureType() == MeasureType::Value, storm::exceptions::InvalidPropertyException, "Invalid measure type in P-operator."); } bool ProbabilityOperatorFormula::isProbabilityOperatorFormula() const { @@ -27,13 +18,9 @@ namespace storm { boost::any ProbabilityOperatorFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const { return visitor.visit(*this, data); } - - ProbabilityOperatorFormula::ProbabilityOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula) : OperatorFormula(optimalityType, bound, subformula) { - // Intentionally left empty. - } std::shared_ptr<Formula> ProbabilityOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const { - return std::make_shared<ProbabilityOperatorFormula>(this->optimalityType, this->bound, this->getSubformula().substitute(substitution)); + return std::make_shared<ProbabilityOperatorFormula>(this->getSubformula().substitute(substitution), this->operatorInformation); } std::ostream& ProbabilityOperatorFormula::writeToStream(std::ostream& out) const { diff --git a/src/logic/ProbabilityOperatorFormula.h b/src/logic/ProbabilityOperatorFormula.h index 1172247d0..786d58b44 100644 --- a/src/logic/ProbabilityOperatorFormula.h +++ b/src/logic/ProbabilityOperatorFormula.h @@ -7,11 +7,7 @@ namespace storm { namespace logic { class ProbabilityOperatorFormula : public OperatorFormula { public: - ProbabilityOperatorFormula(std::shared_ptr<Formula const> const& subformula); - ProbabilityOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula); - ProbabilityOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula); - ProbabilityOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula); - ProbabilityOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula); + ProbabilityOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation()); virtual ~ProbabilityOperatorFormula() { // Intentionally left empty. diff --git a/src/logic/RewardOperatorFormula.cpp b/src/logic/RewardOperatorFormula.cpp index 711f78789..cb5a6dc80 100644 --- a/src/logic/RewardOperatorFormula.cpp +++ b/src/logic/RewardOperatorFormula.cpp @@ -2,22 +2,13 @@ #include "src/logic/FormulaVisitor.h" +#include "src/utility/macros.h" +#include "src/exceptions/InvalidPropertyException.h" + namespace storm { namespace logic { - RewardOperatorFormula::RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, std::shared_ptr<Formula const> const& subformula) : RewardOperatorFormula(rewardModelName, boost::none, boost::none, subformula) { - // Intentionally left empty. - } - - RewardOperatorFormula::RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : RewardOperatorFormula(rewardModelName, boost::none, bound, subformula) { - // Intentionally left empty. - } - - RewardOperatorFormula::RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : RewardOperatorFormula(rewardModelName, boost::optional<OptimizationDirection>(optimalityType), bound, subformula) { - // Intentionally left empty. - } - - RewardOperatorFormula::RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula) : RewardOperatorFormula(rewardModelName, boost::optional<OptimizationDirection>(optimalityType), boost::none, subformula) { - // Intentionally left empty. + RewardOperatorFormula::RewardOperatorFormula(std::shared_ptr<Formula const> const& subformula, boost::optional<std::string> const& rewardModelName, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation), rewardModelName(rewardModelName) { + STORM_LOG_THROW(this->getMeasureType() == MeasureType::Expectation || this->getMeasureType() == MeasureType::Variance, storm::exceptions::InvalidPropertyException, "Invalid measure type in R-operator."); } bool RewardOperatorFormula::isRewardOperatorFormula() const { @@ -49,12 +40,8 @@ namespace storm { this->getSubformula().gatherReferencedRewardModels(referencedRewardModels); } - RewardOperatorFormula::RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula) : OperatorFormula(optimalityType, bound, subformula), rewardModelName(rewardModelName) { - // Intentionally left empty. - } - std::shared_ptr<Formula> RewardOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const { - return std::make_shared<RewardOperatorFormula>(this->rewardModelName, this->optimalityType, this->bound, this->getSubformula().substitute(substitution)); + return std::make_shared<RewardOperatorFormula>(this->getSubformula().substitute(substitution), this->rewardModelName, this->operatorInformation); } std::ostream& RewardOperatorFormula::writeToStream(std::ostream& out) const { diff --git a/src/logic/RewardOperatorFormula.h b/src/logic/RewardOperatorFormula.h index 6bcf015d8..e371ee0b9 100644 --- a/src/logic/RewardOperatorFormula.h +++ b/src/logic/RewardOperatorFormula.h @@ -8,11 +8,7 @@ namespace storm { namespace logic { class RewardOperatorFormula : public OperatorFormula { public: - RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, std::shared_ptr<Formula const> const& subformula); - RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula); - RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula); - RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula); - RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula); + RewardOperatorFormula(std::shared_ptr<Formula const> const& subformula, boost::optional<std::string> const& rewardModelName = boost::none, OperatorInformation const& operatorInformation = OperatorInformation()); virtual ~RewardOperatorFormula() { // Intentionally left empty. diff --git a/src/modelchecker/AbstractModelChecker.cpp b/src/modelchecker/AbstractModelChecker.cpp index ebd760d2e..f79fa373b 100644 --- a/src/modelchecker/AbstractModelChecker.cpp +++ b/src/modelchecker/AbstractModelChecker.cpp @@ -34,8 +34,8 @@ namespace storm { storm::logic::Formula const& formula = checkTask.getFormula(); if (formula.isBoundedUntilFormula()) { return this->computeBoundedUntilProbabilities(checkTask.substituteFormula(formula.asBoundedUntilFormula())); - } else if (formula.isEventuallyFormula()) { - return this->computeEventuallyProbabilities(checkTask.substituteFormula(formula.asEventuallyFormula())); + } else if (formula.isReachabilityProbabilityFormula()) { + return this->computeReachabilityProbabilities(checkTask.substituteFormula(formula.asReachabilityProbabilityFormula())); } else if (formula.isGloballyFormula()) { return this->computeGloballyProbabilities(checkTask.substituteFormula(formula.asGloballyFormula())); } else if (formula.isUntilFormula()) { @@ -56,7 +56,7 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } - std::unique_ptr<CheckResult> AbstractModelChecker::computeEventuallyProbabilities(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> AbstractModelChecker::computeReachabilityProbabilities(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& pathFormula = checkTask.getFormula(); storm::logic::UntilFormula newFormula(storm::logic::Formula::getTrueFormula(), pathFormula.getSubformula().asSharedPointer()); return this->computeUntilProbabilities(checkTask.substituteFormula(newFormula)); @@ -81,7 +81,7 @@ namespace storm { } else if (rewardFormula.isInstantaneousRewardFormula()) { return this->computeInstantaneousRewards(checkTask.substituteFormula(rewardFormula.asInstantaneousRewardFormula())); } else if (rewardFormula.isReachabilityRewardFormula()) { - return this->computeReachabilityRewards(checkTask.substituteFormula(rewardFormula.asEventuallyFormula())); + return this->computeReachabilityRewards(checkTask.substituteFormula(rewardFormula.asReachabilityRewardFormula())); } else if (rewardFormula.isLongRunAverageRewardFormula()) { return this->computeLongRunAverageRewards(checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula())); } else if (rewardFormula.isConditionalRewardFormula()) { @@ -205,7 +205,7 @@ namespace storm { std::unique_ptr<CheckResult> AbstractModelChecker::checkExpectedTimeOperatorFormula(CheckTask<storm::logic::ExpectedTimeOperatorFormula> const& checkTask) { storm::logic::ExpectedTimeOperatorFormula const& stateFormula = checkTask.getFormula(); - STORM_LOG_THROW(stateFormula.getSubformula().isEventuallyFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid."); + STORM_LOG_THROW(stateFormula.getSubformula().isReachabilityExpectedTimeFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid."); std::unique_ptr<CheckResult> result = this->computeExpectedTimes(checkTask.substituteFormula(stateFormula.getSubformula().asEventuallyFormula())); diff --git a/src/modelchecker/AbstractModelChecker.h b/src/modelchecker/AbstractModelChecker.h index 90562659b..c63f00a3c 100644 --- a/src/modelchecker/AbstractModelChecker.h +++ b/src/modelchecker/AbstractModelChecker.h @@ -38,7 +38,7 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeProbabilities(CheckTask<storm::logic::Formula> const& checkTask); virtual std::unique_ptr<CheckResult> computeConditionalProbabilities(CheckTask<storm::logic::ConditionalFormula> const& checkTask); virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(CheckTask<storm::logic::BoundedUntilFormula> const& checkTask); - virtual std::unique_ptr<CheckResult> computeEventuallyProbabilities(CheckTask<storm::logic::EventuallyFormula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeReachabilityProbabilities(CheckTask<storm::logic::EventuallyFormula> const& checkTask); virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask); virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask); virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask); diff --git a/src/parser/FormulaParser.cpp b/src/parser/FormulaParser.cpp index d8fa100c8..7a78b797b 100644 --- a/src/parser/FormulaParser.cpp +++ b/src/parser/FormulaParser.cpp @@ -88,6 +88,18 @@ namespace storm { // A parser used for recognizing the optimality operators. optimalityOperatorStruct optimalityOperator_; + struct measureTypeStruct : qi::symbols<char, storm::logic::MeasureType> { + measureTypeStruct() { + add + ("val", storm::logic::MeasureType::Value) + ("exp", storm::logic::MeasureType::Expectation) + ("var", storm::logic::MeasureType::Variance); + } + }; + + // A parser used for recognizing the measure types. + measureTypeStruct measureType_; + // Parser and manager used for recognizing expressions. storm::parser::ExpressionParser expressionParser; @@ -97,7 +109,8 @@ namespace storm { qi::rule<Iterator, std::vector<std::shared_ptr<storm::logic::Formula>>(), Skipper> start; - qi::rule<Iterator, std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>>(), qi::locals<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::ComparisonType>, boost::optional<double>>, Skipper> operatorInformation; + qi::rule<Iterator, storm::logic::OperatorInformation(storm::logic::MeasureType), qi::locals<storm::logic::MeasureType, boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::ComparisonType>, boost::optional<double>>, Skipper> operatorInformation; + qi::rule<Iterator, storm::logic::MeasureType(), Skipper> measureType; qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> probabilityOperator; qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> rewardOperator; qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> expectedTimeOperator; @@ -147,11 +160,11 @@ namespace storm { std::shared_ptr<storm::logic::Formula> createNextFormula(std::shared_ptr<storm::logic::Formula> const& subformula) const; std::shared_ptr<storm::logic::Formula> createUntilFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, boost::optional<boost::variant<std::pair<double, double>, uint_fast64_t>> const& timeBound, std::shared_ptr<storm::logic::Formula> const& rightSubformula); std::shared_ptr<storm::logic::Formula> createConditionalFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, std::shared_ptr<storm::logic::Formula> const& rightSubformula, storm::logic::FormulaContext context) const; - std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> createOperatorInformation(boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const; - std::shared_ptr<storm::logic::Formula> createLongRunAverageOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; - std::shared_ptr<storm::logic::Formula> createRewardOperatorFormula(boost::optional<std::string> const& rewardModelName, std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; - std::shared_ptr<storm::logic::Formula> createExpectedTimeOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; - std::shared_ptr<storm::logic::Formula> createProbabilityOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula); + storm::logic::OperatorInformation createOperatorInformation(storm::logic::MeasureType const& measureType, boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const; + std::shared_ptr<storm::logic::Formula> createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; + std::shared_ptr<storm::logic::Formula> createRewardOperatorFormula(boost::optional<std::string> const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; + std::shared_ptr<storm::logic::Formula> createExpectedTimeOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; + std::shared_ptr<storm::logic::Formula> createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula); std::shared_ptr<storm::logic::Formula> createBinaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, std::shared_ptr<storm::logic::Formula> const& rightSubformula, storm::logic::BinaryBooleanStateFormula::OperatorType operatorType); std::shared_ptr<storm::logic::Formula> createUnaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula> const& subformula, boost::optional<storm::logic::UnaryBooleanStateFormula::OperatorType> const& operatorType); @@ -301,22 +314,25 @@ namespace storm { pathFormula = conditionalFormula(qi::_r1); pathFormula.name("path formula"); - operatorInformation = (-optimalityOperator_[qi::_a = qi::_1] >> ((relationalOperator_[qi::_b = qi::_1] > qi::double_[qi::_c = qi::_1]) | (qi::lit("=") > qi::lit("?"))))[qi::_val = phoenix::bind(&FormulaParserGrammar::createOperatorInformation, phoenix::ref(*this), qi::_a, qi::_b, qi::_c)]; + measureType = qi::lit("[") >> measureType_ >> qi::lit("]"); + measureType.name("measure type"); + + operatorInformation = qi::eps[qi::_a = qi::_r1] >> (-measureType[qi::_a = qi::_1] >> -optimalityOperator_[qi::_b = qi::_1] >> ((relationalOperator_[qi::_c = qi::_1] > qi::double_[qi::_d = qi::_1]) | (qi::lit("=") > qi::lit("?"))))[qi::_val = phoenix::bind(&FormulaParserGrammar::createOperatorInformation, phoenix::ref(*this), qi::_a, qi::_b, qi::_c, qi::_d)]; operatorInformation.name("operator information"); - longRunAverageOperator = ((qi::lit("LRA") | qi::lit("S")) > operatorInformation > qi::lit("[") > stateFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createLongRunAverageOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; + longRunAverageOperator = ((qi::lit("LRA") | qi::lit("S")) > operatorInformation(storm::logic::MeasureType::Value) > qi::lit("[") > stateFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createLongRunAverageOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; longRunAverageOperator.name("long-run average operator"); rewardModelName = qi::lit("{\"") > label > qi::lit("\"}"); rewardModelName.name("reward model name"); - rewardOperator = (qi::lit("R") > -rewardModelName > operatorInformation > qi::lit("[") > rewardPathFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createRewardOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3)]; + rewardOperator = (qi::lit("R") > -rewardModelName > operatorInformation(storm::logic::MeasureType::Expectation) > qi::lit("[") > rewardPathFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createRewardOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3)]; rewardOperator.name("reward operator"); - expectedTimeOperator = (qi::lit("ET") > operatorInformation > qi::lit("[") > eventuallyFormula(storm::logic::FormulaContext::ExpectedTime) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createExpectedTimeOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; + expectedTimeOperator = (qi::lit("ET") > operatorInformation(storm::logic::MeasureType::Expectation) > qi::lit("[") > eventuallyFormula(storm::logic::FormulaContext::ExpectedTime) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createExpectedTimeOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; expectedTimeOperator.name("expected time operator"); - probabilityOperator = (qi::lit("P") > operatorInformation > qi::lit("[") > pathFormula(storm::logic::FormulaContext::Probability) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createProbabilityOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; + probabilityOperator = (qi::lit("P") > operatorInformation(storm::logic::MeasureType::Value) > qi::lit("[") > pathFormula(storm::logic::FormulaContext::Probability) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createProbabilityOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; probabilityOperator.name("probability operator"); andStateFormula = notStateFormula[qi::_val = qi::_1] >> *(qi::lit("&") >> notStateFormula)[qi::_val = phoenix::bind(&FormulaParserGrammar::createBinaryBooleanStateFormula, phoenix::ref(*this), qi::_val, qi::_1, storm::logic::BinaryBooleanStateFormula::OperatorType::And)]; @@ -459,28 +475,28 @@ namespace storm { return std::shared_ptr<storm::logic::Formula>(new storm::logic::ConditionalFormula(leftSubformula, rightSubformula, context)); } - std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> FormulaParserGrammar::createOperatorInformation(boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const { + storm::logic::OperatorInformation FormulaParserGrammar::createOperatorInformation(storm::logic::MeasureType const& measureType, boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const { if (comparisonType && threshold) { - return std::make_pair(optimizationDirection, storm::logic::Bound<double>(comparisonType.get(), threshold.get())); + return storm::logic::OperatorInformation(measureType, optimizationDirection, storm::logic::Bound<double>(comparisonType.get(), threshold.get())); } else { - return std::make_pair(optimizationDirection, boost::none); + return storm::logic::OperatorInformation(measureType, optimizationDirection, boost::none); } } - std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createLongRunAverageOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { - return std::shared_ptr<storm::logic::Formula>(new storm::logic::LongRunAverageOperatorFormula(operatorInformation.first, operatorInformation.second, subformula)); + std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { + return std::shared_ptr<storm::logic::Formula>(new storm::logic::LongRunAverageOperatorFormula(subformula, operatorInformation)); } - std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createRewardOperatorFormula(boost::optional<std::string> const& rewardModelName, std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { - return std::shared_ptr<storm::logic::Formula>(new storm::logic::RewardOperatorFormula(rewardModelName, operatorInformation.first, operatorInformation.second, subformula)); + std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createRewardOperatorFormula(boost::optional<std::string> const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { + return std::shared_ptr<storm::logic::Formula>(new storm::logic::RewardOperatorFormula(subformula, rewardModelName, operatorInformation)); } - std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createExpectedTimeOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { - return std::shared_ptr<storm::logic::Formula>(new storm::logic::ExpectedTimeOperatorFormula(operatorInformation.first, operatorInformation.second, subformula)); + std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createExpectedTimeOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { + return std::shared_ptr<storm::logic::Formula>(new storm::logic::ExpectedTimeOperatorFormula(subformula, operatorInformation)); } - std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createProbabilityOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) { - return std::shared_ptr<storm::logic::Formula>(new storm::logic::ProbabilityOperatorFormula(operatorInformation.first, operatorInformation.second, subformula)); + std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) { + return std::shared_ptr<storm::logic::Formula>(new storm::logic::ProbabilityOperatorFormula(subformula, operatorInformation)); } std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createBinaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, std::shared_ptr<storm::logic::Formula> const& rightSubformula, storm::logic::BinaryBooleanStateFormula::OperatorType operatorType) { From a3aededd3aec9932acef78d0a4c58c8d65a7bdd1 Mon Sep 17 00:00:00 2001 From: TimQu <tim.quatmann@web.de> Date: Wed, 9 Mar 2016 13:28:50 +0100 Subject: [PATCH 20/33] public access to model ingredients: RewardModel and exitRates Former-commit-id: b8dbe8576eeb3c5a3e78b6046a7c457f326772b6 --- src/models/sparse/MarkovAutomaton.cpp | 5 +++++ src/models/sparse/MarkovAutomaton.h | 7 +++++++ src/models/sparse/Model.h | 29 ++++++++++++++------------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/models/sparse/MarkovAutomaton.cpp b/src/models/sparse/MarkovAutomaton.cpp index 56a6400d1..983bda12e 100644 --- a/src/models/sparse/MarkovAutomaton.cpp +++ b/src/models/sparse/MarkovAutomaton.cpp @@ -55,6 +55,11 @@ namespace storm { return this->exitRates; } + template <typename ValueType, typename RewardModelType> + std::vector<ValueType>& MarkovAutomaton<ValueType, RewardModelType>::getExitRates() { + return this->exitRates; + } + template <typename ValueType, typename RewardModelType> ValueType const& MarkovAutomaton<ValueType, RewardModelType>::getExitRate(storm::storage::sparse::state_type state) const { return this->exitRates[state]; diff --git a/src/models/sparse/MarkovAutomaton.h b/src/models/sparse/MarkovAutomaton.h index 731b845f3..0556ffa9b 100644 --- a/src/models/sparse/MarkovAutomaton.h +++ b/src/models/sparse/MarkovAutomaton.h @@ -94,6 +94,13 @@ namespace storm { */ std::vector<ValueType> const& getExitRates() const; + /*! + * Retrieves the vector representing the exit rates of the states. + * + * @return The exit rate vector of the model. + */ + std::vector<ValueType>& getExitRates(); + /*! * Retrieves the exit rate of the given state. * diff --git a/src/models/sparse/Model.h b/src/models/sparse/Model.h index dc0378348..a458bdff7 100644 --- a/src/models/sparse/Model.h +++ b/src/models/sparse/Model.h @@ -140,6 +140,21 @@ namespace storm { */ storm::storage::SparseMatrix<ValueType>& getTransitionMatrix(); + + /*! + * Retrieves the reward models. + * + * @return A mapping from reward model names to the reward models. + */ + std::unordered_map<std::string, RewardModelType> const& getRewardModels() const; + + /*! + * Retrieves the reward models. + * + * @return A mapping from reward model names to the reward models. + */ + std::unordered_map<std::string, RewardModelType>& getRewardModels(); + /*! * Retrieves whether the model has a reward model with the given name. * @@ -318,20 +333,6 @@ namespace storm { */ void printRewardModelsInformationToStream(std::ostream& out) const; - /*! - * Retrieves the reward models. - * - * @return A mapping from reward model names to the reward models. - */ - std::unordered_map<std::string, RewardModelType> const& getRewardModels() const; - - /*! - * Retrieves the reward models. - * - * @return A mapping from reward model names to the reward models. - */ - std::unordered_map<std::string, RewardModelType>& getRewardModels(); - private: // A matrix representing transition relation. storm::storage::SparseMatrix<ValueType> transitionMatrix; From 69c5ba604e388caef9644063e09a5c0a1063c2c5 Mon Sep 17 00:00:00 2001 From: TimQu <tim.quatmann@web.de> Date: Wed, 9 Mar 2016 13:29:26 +0100 Subject: [PATCH 21/33] Helper functions for parametric stuff Former-commit-id: 288e4de3da6b1deb13fd4e758dbc2b557f375ab1 --- src/utility/constants.cpp | 19 ++++++++++++-- src/utility/constants.h | 3 +++ src/utility/parametric.cpp | 39 +++++++++++++++++++++++++++ src/utility/parametric.h | 54 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 src/utility/parametric.cpp create mode 100644 src/utility/parametric.h diff --git a/src/utility/constants.cpp b/src/utility/constants.cpp index 900482a72..2aa10d23a 100644 --- a/src/utility/constants.cpp +++ b/src/utility/constants.cpp @@ -39,6 +39,7 @@ namespace storm { bool isConstant(ValueType const& a) { return true; } + #ifdef STORM_HAVE_CARL template<> @@ -85,11 +86,11 @@ namespace storm { template<typename ValueType> ValueType simplify(ValueType value) { - // In the general case, we don't to anything here, but merely return the value. If something else is + // In the general case, we don't do anything here, but merely return the value. If something else is // supposed to happen here, the templated function can be specialized for this particular type. return value; } - + #ifdef STORM_HAVE_CARL template<> RationalFunction& simplify(RationalFunction& value); @@ -119,6 +120,17 @@ namespace storm { value.simplify(); return std::move(value); } + + template<> + double convertNumber(RationalNumber const& number){ + return carl::toDouble(number); + } + + template<> + RationalNumber convertNumber(double const& number){ + return carl::rationalize<RationalNumber>(number); + } + #endif template<typename IndexType, typename ValueType> @@ -221,6 +233,9 @@ namespace storm { template RationalFunction& simplify(RationalFunction& value); template RationalFunction&& simplify(RationalFunction&& value); + template double convertNumber(RationalNumber const& number); + template RationalNumber convertNumber(double const& number); + template bool isOne(Interval const& value); template bool isZero(Interval const& value); template bool isConstant(Interval const& value); diff --git a/src/utility/constants.h b/src/utility/constants.h index 8f6d8149e..80222b74f 100644 --- a/src/utility/constants.h +++ b/src/utility/constants.h @@ -50,6 +50,9 @@ namespace storm { template<typename IndexType, typename ValueType> storm::storage::MatrixEntry<IndexType, ValueType>&& simplify(storm::storage::MatrixEntry<IndexType, ValueType>&& matrixEntry); + + template<typename TargetType, typename SourceType> + TargetType convertNumber(SourceType const& number); } } diff --git a/src/utility/parametric.cpp b/src/utility/parametric.cpp new file mode 100644 index 000000000..c45882c42 --- /dev/null +++ b/src/utility/parametric.cpp @@ -0,0 +1,39 @@ +/* + * File: parametric.cpp + * Author: Tim Quatmann + * + * Created by Tim Quatmann on 08/03/16. + */ + +#include <string> + +#include "src/utility/parametric.h" +#include "src/utility/constants.h" +#include "src/utility/macros.h" +#include "src/settings/SettingsManager.h" +#include "src/exceptions/IllegalArgumentException.h" +#include "src/exceptions/NotImplementedException.h" + +#ifdef STORM_HAVE_CARL +#include<carl/numbers/numbers.h> +#include<carl/core/VariablePool.h> +#endif + +namespace storm { + namespace utility{ + namespace parametric { + +#ifdef STORM_HAVE_CARL + template<> + typename CoefficientType<storm::RationalFunction>::type evaluate<storm::RationalFunction>(storm::RationalFunction const& function, std::map<typename VariableType<storm::RationalFunction>::type, typename CoefficientType<storm::RationalFunction>::type> const& valuation){ + return function.evaluate(valuation); + } + + template<> + typename CoefficientType<storm::RationalFunction>::type getConstantPart<storm::RationalFunction>(storm::RationalFunction const& function){ + return function.constantPart(); + } +#endif + } + } +} diff --git a/src/utility/parametric.h b/src/utility/parametric.h new file mode 100644 index 000000000..2ebf1e18c --- /dev/null +++ b/src/utility/parametric.h @@ -0,0 +1,54 @@ +// +// parametric.h +// +// Created by Tim Quatmann on 08/03/16. +// +// + +#ifndef STORM_UTILITY_PARAMETRIC_H +#define STORM_UTILITY_PARAMETRIC_H + +#include "src/adapters/CarlAdapter.h" + + +namespace storm { + namespace utility { + namespace parametric { + + /*! + * Access the type of variables from a given function type + */ + template<typename FunctionType> + struct VariableType { typedef void type; }; + /*! + * Acess the type of coefficients from a given function type + */ + template<typename FunctionType> + struct CoefficientType { typedef void type; }; + +#ifdef STORM_HAVE_CARL + template<> + struct VariableType<storm::RationalFunction> { typedef storm::Variable type; }; + template<> + struct CoefficientType<storm::RationalFunction> { typedef storm::RationalNumber type; }; +#endif + + /*! + * Evaluates the given function wrt. the given valuation + */ + template<typename FunctionType> + typename CoefficientType<FunctionType>::type evaluate(FunctionType const& function, std::map<typename VariableType<FunctionType>::type, typename CoefficientType<FunctionType>::type> const& valuation); + + /*! + * Retrieves the constant part of the given function. + */ + template<typename FunctionType> + typename CoefficientType<FunctionType>::type getConstantPart(FunctionType const& function); + + } + + } +} + + +#endif /* STORM_UTILITY_PARAMETRIC_H */ From 6e8602413e8524f74cbc26f940df5ddaaaa5d5a7 Mon Sep 17 00:00:00 2001 From: TimQu <tim.quatmann@web.de> Date: Wed, 9 Mar 2016 13:29:42 +0100 Subject: [PATCH 22/33] ModelInstantiator + test Former-commit-id: f3c998006745041f98df1176aa8eeec9bd935028 --- src/models/sparse/StochasticTwoPlayerGame.cpp | 2 +- src/utility/ModelInstantiator.cpp | 161 +++++++++++ src/utility/ModelInstantiator.h | 158 +++++++++++ .../utility/ModelInstantiatorTest.cpp | 266 ++++++++++++++++++ test/functional/utility/brp16_2.pm | 146 ++++++++++ test/functional/utility/coin2_2.pm | 56 ++++ 6 files changed, 788 insertions(+), 1 deletion(-) create mode 100644 src/utility/ModelInstantiator.cpp create mode 100644 src/utility/ModelInstantiator.h create mode 100644 test/functional/utility/ModelInstantiatorTest.cpp create mode 100644 test/functional/utility/brp16_2.pm create mode 100644 test/functional/utility/coin2_2.pm diff --git a/src/models/sparse/StochasticTwoPlayerGame.cpp b/src/models/sparse/StochasticTwoPlayerGame.cpp index c8ce13bec..7a6ea02a1 100644 --- a/src/models/sparse/StochasticTwoPlayerGame.cpp +++ b/src/models/sparse/StochasticTwoPlayerGame.cpp @@ -65,7 +65,7 @@ namespace storm { // template class StochasticTwoPlayerGame<float>; #ifdef STORM_HAVE_CARL -// template class StochasticTwoPlayerGame<storm::RationalFunction>; + template class StochasticTwoPlayerGame<storm::RationalFunction>; #endif } // namespace sparse diff --git a/src/utility/ModelInstantiator.cpp b/src/utility/ModelInstantiator.cpp new file mode 100644 index 000000000..cb8c62535 --- /dev/null +++ b/src/utility/ModelInstantiator.cpp @@ -0,0 +1,161 @@ +/* + * File: ModelInstantiator.cpp + * Author: Tim Quatmann + * + * Created on February 23, 2016 + */ + +#include "src/utility/ModelInstantiator.h" +#include "src/models/sparse/StandardRewardModel.h" + +namespace storm { + namespace utility { + + template<typename ParametricSparseModelType, typename ConstantSparseModelType> + ModelInstantiator<ParametricSparseModelType, ConstantSparseModelType>::ModelInstantiator(ParametricSparseModelType const& parametricModel){ + //Now pre-compute the information for the equation system. + initializeModelSpecificData(parametricModel); + initializeMatrixMapping(this->instantiatedModel->getTransitionMatrix(), this->functions, this->matrixMapping, parametricModel.getTransitionMatrix()); + + for(auto& rewModel : this->instantiatedModel->getRewardModels()) { + if(rewModel.second.hasStateRewards()){ + initializeVectorMapping(rewModel.second.getStateRewardVector(), this->functions, this->vectorMapping, parametricModel.getRewardModel(rewModel.first).getStateRewardVector()); + } + if(rewModel.second.hasStateActionRewards()){ + initializeVectorMapping(rewModel.second.getStateActionRewardVector(), this->functions, this->vectorMapping, parametricModel.getRewardModel(rewModel.first).getStateActionRewardVector()); + } + if(rewModel.second.hasTransitionRewards()){ + initializeMatrixMapping(rewModel.second.getTransitionRewardMatrix(), this->functions, this->matrixMapping, parametricModel.getRewardModel(rewModel.first).getTransitionRewardMatrix()); + } + } + } + + template<typename ParametricSparseModelType, typename ConstantType> + ModelInstantiator<ParametricSparseModelType, ConstantType>::~ModelInstantiator() { + //Intentionally left empty + } + + template<typename ParametricSparseModelType, typename ConstantSparseModelType> + storm::storage::SparseMatrix<typename ConstantSparseModelType::ValueType> ModelInstantiator<ParametricSparseModelType, ConstantSparseModelType>::buildDummyMatrix(storm::storage::SparseMatrix<ParametricType> const& parametricMatrix) const{ + storm::storage::SparseMatrixBuilder<ConstantType> matrixBuilder(parametricMatrix.getRowCount(), + parametricMatrix.getColumnCount(), + parametricMatrix.getEntryCount(), + true, // no force dimensions + true, //Custom row grouping + parametricMatrix.getRowGroupCount()); + for(std::size_t rowGroup = 0; rowGroup < parametricMatrix.getRowGroupCount(); ++rowGroup){ + matrixBuilder.newRowGroup(parametricMatrix.getRowGroupIndices()[rowGroup]); + for(std::size_t row = parametricMatrix.getRowGroupIndices()[rowGroup]; row < parametricMatrix.getRowGroupIndices()[rowGroup+1]; ++row){ + ConstantType dummyValue = storm::utility::one<ConstantType>(); + for(auto const& paramEntry : parametricMatrix.getRow(row)){ + matrixBuilder.addNextValue(row, paramEntry.getColumn(), dummyValue); + dummyValue = storm::utility::zero<ConstantType>(); + } + } + } + return matrixBuilder.build(); + } + + template<typename ParametricSparseModelType, typename ConstantSparseModelType> + std::unordered_map<std::string, typename ConstantSparseModelType::RewardModelType> ModelInstantiator<ParametricSparseModelType, ConstantSparseModelType>::buildDummyRewardModels(std::unordered_map<std::string, typename ParametricSparseModelType::RewardModelType> const& parametricRewardModel) const { + std::unordered_map<std::string, typename ConstantSparseModelType::RewardModelType> result; + for(auto const& paramRewardModel : parametricRewardModel){ + auto const& rewModel = paramRewardModel.second; + boost::optional<std::vector<ConstantType>> optionalStateRewardVector; + if(rewModel.hasStateRewards()) { + optionalStateRewardVector = std::vector<ConstantType>(rewModel.getStateRewardVector().size()); + } + boost::optional<std::vector<ConstantType>> optionalStateActionRewardVector; + if(rewModel.hasStateActionRewards()) { + optionalStateActionRewardVector = std::vector<ConstantType>(rewModel.getStateActionRewardVector().size()); + } + boost::optional<storm::storage::SparseMatrix<ConstantType>> optionalTransitionRewardMatrix; + if(rewModel.hasTransitionRewards()) { + optionalTransitionRewardMatrix = buildDummyMatrix(rewModel.getTransitionRewardMatrix()); + } + result.insert(std::make_pair(paramRewardModel.first, + storm::models::sparse::StandardRewardModel<ConstantType>(std::move(optionalStateRewardVector), std::move(optionalStateActionRewardVector), std::move(optionalTransitionRewardMatrix)) + )); + } + return result; + } + + template<typename ParametricSparseModelType, typename ConstantSparseModelType> + void ModelInstantiator<ParametricSparseModelType, ConstantSparseModelType>::initializeMatrixMapping(storm::storage::SparseMatrix<ConstantType>& constantMatrix, + std::unordered_map<ParametricType, ConstantType>& functions, + std::vector<std::pair<typename storm::storage::SparseMatrix<ConstantType>::iterator, ConstantType*>>& mapping, + storm::storage::SparseMatrix<ParametricType> const& parametricMatrix) const{ + ConstantType dummyValue = storm::utility::one<ConstantType>(); + auto constantEntryIt = constantMatrix.begin(); + auto parametricEntryIt = parametricMatrix.begin(); + while(parametricEntryIt != parametricMatrix.end()){ + STORM_LOG_ASSERT(parametricEntryIt->getColumn() == constantEntryIt->getColumn(), "Entries of parametric and constant matrix are not at the same position"); + if(storm::utility::isConstant(parametricEntryIt->getValue())){ + //Constant entries can be inserted directly + constantEntryIt->setValue(storm::utility::convertNumber<ConstantType>(storm::utility::parametric::getConstantPart(parametricEntryIt->getValue()))); + } else { + //insert the new function and store that the current constantMatrix entry needs to be set to the value of this function + auto functionsIt = functions.insert(std::make_pair(parametricEntryIt->getValue(), dummyValue)).first; + mapping.emplace_back(std::make_pair(constantEntryIt, &(functionsIt->second))); + //Note that references to elements of an unordered map remain valid after calling unordered_map::insert. + } + ++constantEntryIt; + ++parametricEntryIt; + } + STORM_LOG_ASSERT(constantEntryIt == constantMatrix.end(), "Parametric matrix seems to have more or less entries then the constant matrix"); + //TODO: is this necessary? + constantMatrix.updateNonzeroEntryCount(); + } + + template<typename ParametricSparseModelType, typename ConstantSparseModelType> + void ModelInstantiator<ParametricSparseModelType, ConstantSparseModelType>::initializeVectorMapping(std::vector<ConstantType>& constantVector, + std::unordered_map<ParametricType, ConstantType>& functions, + std::vector<std::pair<typename std::vector<ConstantType>::iterator, ConstantType*>>& mapping, + std::vector<ParametricType> const& parametricVector) const{ + ConstantType dummyValue = storm::utility::one<ConstantType>(); + auto constantEntryIt = constantVector.begin(); + auto parametricEntryIt = parametricVector.begin(); + while(parametricEntryIt != parametricVector.end()){ + if(storm::utility::isConstant(storm::utility::simplify(*parametricEntryIt))){ + //Constant entries can be inserted directly + *constantEntryIt = storm::utility::convertNumber<ConstantType>(storm::utility::parametric::getConstantPart(*parametricEntryIt)); + } else { + //insert the new function and store that the current constantVector entry needs to be set to the value of this function + auto functionsIt = functions.insert(std::make_pair(*parametricEntryIt, dummyValue)).first; + mapping.emplace_back(std::make_pair(constantEntryIt, &(functionsIt->second))); + //Note that references to elements of an unordered map remain valid after calling unordered_map::insert. + } + ++constantEntryIt; + ++parametricEntryIt; + } + STORM_LOG_ASSERT(constantEntryIt == constantVector.end(), "Parametric vector seems to have more or less entries then the constant vector"); + } + + template<typename ParametricSparseModelType, typename ConstantSparseModelType> + ConstantSparseModelType const& ModelInstantiator<ParametricSparseModelType, ConstantSparseModelType>::instantiate(std::map<VariableType, CoefficientType>const& valuation){ + //Write results into the placeholders + for(auto& functionResult : this->functions){ + functionResult.second=storm::utility::convertNumber<ConstantType>( + storm::utility::parametric::evaluate(functionResult.first, valuation)); + } + + //Write the instantiated values to the matrices and vectors according to the stored mappings + for(auto& entryValuePair : this->matrixMapping){ + entryValuePair.first->setValue(*(entryValuePair.second)); + } + for(auto& entryValuePair : this->vectorMapping){ + *(entryValuePair.first)=*(entryValuePair.second); + } + + return *this->instantiatedModel; + } + +#ifdef STORM_HAVE_CARL + template class ModelInstantiator<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::models::sparse::Dtmc<double>>; + template class ModelInstantiator<storm::models::sparse::Mdp<storm::RationalFunction>, storm::models::sparse::Mdp<double>>; + template class ModelInstantiator<storm::models::sparse::Ctmc<storm::RationalFunction>, storm::models::sparse::Ctmc<double>>; + template class ModelInstantiator<storm::models::sparse::MarkovAutomaton<storm::RationalFunction>, storm::models::sparse::MarkovAutomaton<double>>; + template class ModelInstantiator<storm::models::sparse::StochasticTwoPlayerGame<storm::RationalFunction>, storm::models::sparse::StochasticTwoPlayerGame<double>>; +#endif + } //namespace utility +} //namespace storm \ No newline at end of file diff --git a/src/utility/ModelInstantiator.h b/src/utility/ModelInstantiator.h new file mode 100644 index 000000000..939e71e2d --- /dev/null +++ b/src/utility/ModelInstantiator.h @@ -0,0 +1,158 @@ +/* + * File: ModelInstantiator.h + * Author: Tim Quatmann + * + * Created on February 23, 2016 + */ + +#ifndef STORM_UTILITY_MODELINSTANTIATOR_H +#define STORM_UTILITY_MODELINSTANTIATOR_H + +#include <unordered_map> +#include <memory> +#include <type_traits> + +#include "src/models/sparse/Dtmc.h" +#include "src/models/sparse/Mdp.h" +#include "src/models/sparse/Ctmc.h" +#include "src/models/sparse/MarkovAutomaton.h" +#include "src/models/sparse/StochasticTwoPlayerGame.h" +#include "src/utility/parametric.h" +#include "src/utility/constants.h" + +namespace storm { + namespace utility{ + + + /*! + * This class allows efficient instantiation of the given parametric model. + * The key to efficiency is to evaluate every distinct transition- (or reward-) function only once + * instead of evaluating the same function for each occurrence in the model. + */ + template<typename ParametricSparseModelType, typename ConstantSparseModelType> + class ModelInstantiator { + public: + typedef typename ParametricSparseModelType::ValueType ParametricType; + typedef typename storm::utility::parametric::VariableType<ParametricType>::type VariableType; + typedef typename storm::utility::parametric::CoefficientType<ParametricType>::type CoefficientType; + typedef typename ConstantSparseModelType::ValueType ConstantType; + + /*! + * Constructs a ModelInstantiator + * @param parametricModel The model that is to be instantiated + */ + ModelInstantiator(ParametricSparseModelType const& parametricModel); + + /*! + * Destructs the ModelInstantiator + */ + virtual ~ModelInstantiator(); + + /*! + * Evaluates the occurring parametric functions and retrieves the instantiated model + * @param valuation Maps each occurring variables to the value with which it should be substituted + * @return The instantiated model + */ + ConstantSparseModelType const& instantiate(std::map<VariableType, CoefficientType>const& valuation); + + + private: + /*! + * Initializes the instantiatedModel with dummy data by considering the model-specific ingredients. + * Also initializes other model-specific data, e.g., the exitRate vector of a markov automaton + */ + template<typename PMT = ParametricSparseModelType> + typename std::enable_if< + std::is_same<PMT,storm::models::sparse::Dtmc<typename ParametricSparseModelType::ValueType>>::value || + std::is_same<PMT,storm::models::sparse::Mdp<typename ParametricSparseModelType::ValueType>>::value || + std::is_same<PMT,storm::models::sparse::Ctmc<typename ParametricSparseModelType::ValueType>>::value + >::type + initializeModelSpecificData(PMT const& parametricModel) { + auto stateLabelingCopy = parametricModel.getStateLabeling(); + auto choiceLabelingCopy = parametricModel.getOptionalChoiceLabeling(); + this->instantiatedModel = std::make_shared<ConstantSparseModelType>(buildDummyMatrix(parametricModel.getTransitionMatrix()), std::move(stateLabelingCopy), buildDummyRewardModels(parametricModel.getRewardModels()), std::move(choiceLabelingCopy)); + } + + template<typename PMT = ParametricSparseModelType> + typename std::enable_if< + std::is_same<PMT,storm::models::sparse::MarkovAutomaton<typename ParametricSparseModelType::ValueType>>::value + >::type + initializeModelSpecificData(PMT const& parametricModel) { + auto stateLabelingCopy = parametricModel.getStateLabeling(); + auto markovianStatesCopy = parametricModel.getMarkovianStates(); + auto choiceLabelingCopy = parametricModel.getOptionalChoiceLabeling(); + std::vector<ConstantType> exitRates(parametricModel.getExitRates().size(), storm::utility::one<ConstantType>()); + this->instantiatedModel = std::make_shared<ConstantSparseModelType>(buildDummyMatrix(parametricModel.getTransitionMatrix()), std::move(stateLabelingCopy), std::move(markovianStatesCopy), std::move(exitRates), buildDummyRewardModels(parametricModel.getRewardModels()), std::move(choiceLabelingCopy)); + + initializeVectorMapping(this->instantiatedModel->getExitRates(), this->functions, this->vectorMapping, parametricModel.getExitRates()); + } + + template<typename PMT = ParametricSparseModelType> + typename std::enable_if< + std::is_same<PMT,storm::models::sparse::StochasticTwoPlayerGame<typename ParametricSparseModelType::ValueType>>::value + >::type + initializeModelSpecificData(PMT const& parametricModel) { + auto player1MatrixCopy = parametricModel.getPlayer1Matrix(); + auto stateLabelingCopy = parametricModel.getStateLabeling(); + boost::optional<std::vector<typename storm::models::sparse::LabelSet>> player1ChoiceLabeling, player2ChoiceLabeling; + if(parametricModel.hasPlayer1ChoiceLabeling()) player1ChoiceLabeling = parametricModel.getPlayer1ChoiceLabeling(); + if(parametricModel.hasPlayer2ChoiceLabeling()) player2ChoiceLabeling = parametricModel.getPlayer2ChoiceLabeling(); + this->instantiatedModel = std::make_shared<ConstantSparseModelType>(std::move(player1MatrixCopy), buildDummyMatrix(parametricModel.getTransitionMatrix()), std::move(stateLabelingCopy), buildDummyRewardModels(parametricModel.getRewardModels()), std::move(player1ChoiceLabeling), std::move(player2ChoiceLabeling)); + } + + /*! + * Creates a matrix that has entries at the same position as the given matrix. + * The returned matrix is a stochastic matrix, i.e., the rows sum up to one. + */ + storm::storage::SparseMatrix<ConstantType> buildDummyMatrix(storm::storage::SparseMatrix<ParametricType> const& parametricMatrix) const; + + /*! + * Creates a copy of the given reward models with the same names and with state(action)rewards / transitionrewards having the same entry-count and entry-positions. + */ + std::unordered_map<std::string, typename ConstantSparseModelType::RewardModelType> buildDummyRewardModels(std::unordered_map<std::string, typename ParametricSparseModelType::RewardModelType> const& parametricRewardModel) const; + + /*! + * Connects the occurring functions with the corresponding matrix entries + * + * @note constantMatrix and parametricMatrix should have entries at the same positions + * + * @param constantMatrix The matrix to which the evaluation results are written + * @param functions Occurring functions are inserted in this map + * @param mapping The connections of functions to matrix entries are push_backed into this + * @param parametricMatrix the source matrix with the functions to consider. + */ + void initializeMatrixMapping(storm::storage::SparseMatrix<ConstantType>& constantMatrix, + std::unordered_map<ParametricType, ConstantType>& functions, + std::vector<std::pair<typename storm::storage::SparseMatrix<ConstantType>::iterator, ConstantType*>>& mapping, + storm::storage::SparseMatrix<ParametricType> const& parametricMatrix) const; + + /*! + * Connects the occurring functions with the corresponding vector entries + * + * @note constantVector and parametricVector should have the same size + * + * @param constantVector The vector to which the evaluation results are written + * @param functions Occurring functions with their placeholders are inserted in this map + * @param mapping The connections of functions to vector entries are push_backed into this + * @param parametricVector the source vector with the functions to consider. + */ + void initializeVectorMapping(std::vector<ConstantType>& constantVector, + std::unordered_map<ParametricType, ConstantType>& functions, + std::vector<std::pair<typename std::vector<ConstantType>::iterator, ConstantType*>>& mapping, + std::vector<ParametricType> const& parametricVector) const; + + /// The resulting model + std::shared_ptr<ConstantSparseModelType> instantiatedModel; + /// the occurring functions together with the corresponding placeholders for their evaluated result + std::unordered_map<ParametricType, ConstantType> functions; + /// Connection of matrix entries with placeholders + std::vector<std::pair<typename storm::storage::SparseMatrix<ConstantType>::iterator, ConstantType*>> matrixMapping; + /// Connection of Vector entries with placeholders + std::vector<std::pair<typename std::vector<ConstantType>::iterator, ConstantType*>> vectorMapping; + + + }; + }//Namespace utility +} //namespace storm +#endif /* STORM_UTILITY_MODELINSTANTIATOR_H */ + diff --git a/test/functional/utility/ModelInstantiatorTest.cpp b/test/functional/utility/ModelInstantiatorTest.cpp new file mode 100644 index 000000000..af8f5b8d2 --- /dev/null +++ b/test/functional/utility/ModelInstantiatorTest.cpp @@ -0,0 +1,266 @@ +#include "gtest/gtest.h" +#include "storm-config.h" + +#ifdef STORM_HAVE_CARL + +#include "src/adapters/CarlAdapter.h" +#include<carl/numbers/numbers.h> +#include<carl/core/VariablePool.h> + + +#include "src/settings/SettingsManager.h" +#include "src/settings/modules/GeneralSettings.h" + +#include "utility/storm.h" +#include "utility/ModelInstantiator.h" +#include "src/models/sparse/Model.h" +#include "src/models/sparse/Dtmc.h" +#include "src/models/sparse/Mdp.h" + +TEST(ModelInstantiatorTest, Brp_Prob) { + carl::VariablePool::getInstance().clear(); + + std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm"; + std::string const& formulaAsString = "P=? [F s=5 ]"; + std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::parseProgram(programFile); + program.checkValidity(); + std::vector<std::shared_ptr<storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaAsString, program); + ASSERT_TRUE(formulas.size()==1); + // Parametric model + typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]); + options.addConstantDefinitionsFromString(program, constantsAsString); + options.preserveFormula(*formulas[0]); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + storm::utility::ModelInstantiator<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::models::sparse::Dtmc<double>> modelInstantiator(*dtmc); + EXPECT_FALSE(dtmc->hasRewardModel()); + + { + std::map<storm::Variable, storm::RationalNumber> valuation; + storm::Variable const& pL = carl::VariablePool::getInstance().findVariableWithName("pL"); + ASSERT_NE(pL, carl::Variable::NO_VARIABLE); + storm::Variable const& pK = carl::VariablePool::getInstance().findVariableWithName("pK"); + ASSERT_NE(pK, carl::Variable::NO_VARIABLE); + valuation.insert(std::make_pair(pL,carl::rationalize<storm::RationalNumber>(0.8))); + valuation.insert(std::make_pair(pK,carl::rationalize<storm::RationalNumber>(0.9))); + + storm::models::sparse::Dtmc<double> const& instantiated(modelInstantiator.instantiate(valuation)); + + ASSERT_EQ(dtmc->getTransitionMatrix().getRowGroupIndices(), instantiated.getTransitionMatrix().getRowGroupIndices()); + for(std::size_t rowGroup = 0; rowGroup < dtmc->getTransitionMatrix().getRowGroupCount(); ++rowGroup){ + for(std::size_t row = dtmc->getTransitionMatrix().getRowGroupIndices()[rowGroup]; row < dtmc->getTransitionMatrix().getRowGroupIndices()[rowGroup+1]; ++row){ + auto instantiatedEntry = instantiated.getTransitionMatrix().getRow(row).begin(); + for(auto const& paramEntry : dtmc->getTransitionMatrix().getRow(row)){ + EXPECT_EQ(paramEntry.getColumn(), instantiatedEntry->getColumn()); + double evaluatedValue = carl::toDouble(paramEntry.getValue().evaluate(valuation)); + EXPECT_EQ(evaluatedValue, instantiatedEntry->getValue()); + ++instantiatedEntry; + } + EXPECT_EQ(instantiated.getTransitionMatrix().getRow(row).end(),instantiatedEntry); + } + } + EXPECT_EQ(dtmc->getStateLabeling(), instantiated.getStateLabeling()); + EXPECT_EQ(dtmc->getOptionalChoiceLabeling(), instantiated.getOptionalChoiceLabeling()); + + storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<double>> modelchecker(instantiated); + std::unique_ptr<storm::modelchecker::CheckResult> chkResult = modelchecker.check(*formulas[0]); + storm::modelchecker::ExplicitQuantitativeCheckResult<double>& quantitativeChkResult = chkResult->asExplicitQuantitativeCheckResult<double>(); + EXPECT_NEAR(0.2989278941, quantitativeChkResult[*instantiated.getInitialStates().begin()], storm::settings::generalSettings().getPrecision()); + } + + { + std::map<storm::Variable, storm::RationalNumber> valuation; + storm::Variable const& pL = carl::VariablePool::getInstance().findVariableWithName("pL"); + ASSERT_NE(pL, carl::Variable::NO_VARIABLE); + storm::Variable const& pK = carl::VariablePool::getInstance().findVariableWithName("pK"); + ASSERT_NE(pK, carl::Variable::NO_VARIABLE); + valuation.insert(std::make_pair(pL,carl::rationalize<storm::RationalNumber>(1))); + valuation.insert(std::make_pair(pK,carl::rationalize<storm::RationalNumber>(1))); + + storm::models::sparse::Dtmc<double> const& instantiated(modelInstantiator.instantiate(valuation)); + + ASSERT_EQ(dtmc->getTransitionMatrix().getRowGroupIndices(), instantiated.getTransitionMatrix().getRowGroupIndices()); + for(std::size_t rowGroup = 0; rowGroup < dtmc->getTransitionMatrix().getRowGroupCount(); ++rowGroup){ + for(std::size_t row = dtmc->getTransitionMatrix().getRowGroupIndices()[rowGroup]; row < dtmc->getTransitionMatrix().getRowGroupIndices()[rowGroup+1]; ++row){ + auto instantiatedEntry = instantiated.getTransitionMatrix().getRow(row).begin(); + for(auto const& paramEntry : dtmc->getTransitionMatrix().getRow(row)){ + EXPECT_EQ(paramEntry.getColumn(), instantiatedEntry->getColumn()); + double evaluatedValue = carl::toDouble(paramEntry.getValue().evaluate(valuation)); + EXPECT_EQ(evaluatedValue, instantiatedEntry->getValue()); + ++instantiatedEntry; + } + EXPECT_EQ(instantiated.getTransitionMatrix().getRow(row).end(),instantiatedEntry); + } + } + EXPECT_EQ(dtmc->getStateLabeling(), instantiated.getStateLabeling()); + EXPECT_EQ(dtmc->getOptionalChoiceLabeling(), instantiated.getOptionalChoiceLabeling()); + + storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<double>> modelchecker(instantiated); + std::unique_ptr<storm::modelchecker::CheckResult> chkResult = modelchecker.check(*formulas[0]); + storm::modelchecker::ExplicitQuantitativeCheckResult<double>& quantitativeChkResult = chkResult->asExplicitQuantitativeCheckResult<double>(); + EXPECT_EQ(0.0 , quantitativeChkResult[*instantiated.getInitialStates().begin()]); + } + + { + std::map<storm::Variable, storm::RationalNumber> valuation; + storm::Variable const& pL = carl::VariablePool::getInstance().findVariableWithName("pL"); + ASSERT_NE(pL, carl::Variable::NO_VARIABLE); + storm::Variable const& pK = carl::VariablePool::getInstance().findVariableWithName("pK"); + ASSERT_NE(pK, carl::Variable::NO_VARIABLE); + valuation.insert(std::make_pair(pL,carl::rationalize<storm::RationalNumber>(1))); + valuation.insert(std::make_pair(pK,carl::rationalize<storm::RationalNumber>(0.9))); + + storm::models::sparse::Dtmc<double> const& instantiated(modelInstantiator.instantiate(valuation)); + + ASSERT_EQ(dtmc->getTransitionMatrix().getRowGroupIndices(), instantiated.getTransitionMatrix().getRowGroupIndices()); + for(std::size_t rowGroup = 0; rowGroup < dtmc->getTransitionMatrix().getRowGroupCount(); ++rowGroup){ + for(std::size_t row = dtmc->getTransitionMatrix().getRowGroupIndices()[rowGroup]; row < dtmc->getTransitionMatrix().getRowGroupIndices()[rowGroup+1]; ++row){ + auto instantiatedEntry = instantiated.getTransitionMatrix().getRow(row).begin(); + for(auto const& paramEntry : dtmc->getTransitionMatrix().getRow(row)){ + EXPECT_EQ(paramEntry.getColumn(), instantiatedEntry->getColumn()); + double evaluatedValue = carl::toDouble(paramEntry.getValue().evaluate(valuation)); + EXPECT_EQ(evaluatedValue, instantiatedEntry->getValue()); + ++instantiatedEntry; + } + EXPECT_EQ(instantiated.getTransitionMatrix().getRow(row).end(),instantiatedEntry); + } + } + EXPECT_EQ(dtmc->getStateLabeling(), instantiated.getStateLabeling()); + EXPECT_EQ(dtmc->getOptionalChoiceLabeling(), instantiated.getOptionalChoiceLabeling()); + + storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<double>> modelchecker(instantiated); + std::unique_ptr<storm::modelchecker::CheckResult> chkResult = modelchecker.check(*formulas[0]); + storm::modelchecker::ExplicitQuantitativeCheckResult<double>& quantitativeChkResult = chkResult->asExplicitQuantitativeCheckResult<double>(); + EXPECT_NEAR(0.01588055832, quantitativeChkResult[*instantiated.getInitialStates().begin()], storm::settings::generalSettings().getPrecision()); + } +} + +TEST(ModelInstantiatorTest, Brp_Rew) { + carl::VariablePool::getInstance().clear(); + + std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm"; + std::string const& formulaAsString = "R=? [F ((s=5) | (s=0&srep=3)) ]"; + std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::parseProgram(programFile); + program.checkValidity(); + std::vector<std::shared_ptr<storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaAsString, program); + ASSERT_TRUE(formulas.size()==1); + // Parametric model + typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]); + options.addConstantDefinitionsFromString(program, constantsAsString); + options.preserveFormula(*formulas[0]); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + storm::utility::ModelInstantiator<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::models::sparse::Dtmc<double>> modelInstantiator(*dtmc); + + { + std::map<storm::Variable, storm::RationalNumber> valuation; + storm::Variable const& pL = carl::VariablePool::getInstance().findVariableWithName("pL"); + ASSERT_NE(pL, carl::Variable::NO_VARIABLE); + storm::Variable const& pK = carl::VariablePool::getInstance().findVariableWithName("pK"); + ASSERT_NE(pK, carl::Variable::NO_VARIABLE); + storm::Variable const& TOMsg = carl::VariablePool::getInstance().findVariableWithName("TOMsg"); + ASSERT_NE(pK, carl::Variable::NO_VARIABLE); + storm::Variable const& TOAck = carl::VariablePool::getInstance().findVariableWithName("TOAck"); + ASSERT_NE(pK, carl::Variable::NO_VARIABLE); + valuation.insert(std::make_pair(pL,carl::rationalize<storm::RationalNumber>(0.9))); + valuation.insert(std::make_pair(pK,carl::rationalize<storm::RationalNumber>(0.3))); + valuation.insert(std::make_pair(TOMsg,carl::rationalize<storm::RationalNumber>(0.3))); + valuation.insert(std::make_pair(TOAck,carl::rationalize<storm::RationalNumber>(0.5))); + + storm::models::sparse::Dtmc<double> const& instantiated(modelInstantiator.instantiate(valuation)); + + ASSERT_EQ(dtmc->getTransitionMatrix().getRowGroupIndices(), instantiated.getTransitionMatrix().getRowGroupIndices()); + for(std::size_t rowGroup = 0; rowGroup < dtmc->getTransitionMatrix().getRowGroupCount(); ++rowGroup){ + for(std::size_t row = dtmc->getTransitionMatrix().getRowGroupIndices()[rowGroup]; row < dtmc->getTransitionMatrix().getRowGroupIndices()[rowGroup+1]; ++row){ + auto instantiatedEntry = instantiated.getTransitionMatrix().getRow(row).begin(); + for(auto const& paramEntry : dtmc->getTransitionMatrix().getRow(row)){ + EXPECT_EQ(paramEntry.getColumn(), instantiatedEntry->getColumn()); + double evaluatedValue = carl::toDouble(paramEntry.getValue().evaluate(valuation)); + EXPECT_EQ(evaluatedValue, instantiatedEntry->getValue()); + ++instantiatedEntry; + } + EXPECT_EQ(instantiated.getTransitionMatrix().getRow(row).end(),instantiatedEntry); + } + } + ASSERT_TRUE(instantiated.hasUniqueRewardModel()); + EXPECT_FALSE(instantiated.getUniqueRewardModel()->second.hasStateRewards()); + EXPECT_FALSE(instantiated.getUniqueRewardModel()->second.hasTransitionRewards()); + EXPECT_TRUE(instantiated.getUniqueRewardModel()->second.hasStateActionRewards()); + ASSERT_TRUE(dtmc->getUniqueRewardModel()->second.hasStateActionRewards()); + std::size_t stateActionEntries = dtmc->getUniqueRewardModel()->second.getStateActionRewardVector().size(); + ASSERT_EQ(stateActionEntries, instantiated.getUniqueRewardModel()->second.getStateActionRewardVector().size()); + for(std::size_t i =0; i<stateActionEntries; ++i){ + double evaluatedValue = carl::toDouble(dtmc->getUniqueRewardModel()->second.getStateActionRewardVector()[i].evaluate(valuation)); + EXPECT_EQ(evaluatedValue, instantiated.getUniqueRewardModel()->second.getStateActionRewardVector()[i]); + } + EXPECT_EQ(dtmc->getStateLabeling(), instantiated.getStateLabeling()); + EXPECT_EQ(dtmc->getOptionalChoiceLabeling(), instantiated.getOptionalChoiceLabeling()); + + storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<double>> modelchecker(instantiated); + std::unique_ptr<storm::modelchecker::CheckResult> chkResult = modelchecker.check(*formulas[0]); + storm::modelchecker::ExplicitQuantitativeCheckResult<double>& quantitativeChkResult = chkResult->asExplicitQuantitativeCheckResult<double>(); + EXPECT_NEAR(1.308324495, quantitativeChkResult[*instantiated.getInitialStates().begin()], storm::settings::generalSettings().getPrecision()); + } + +} + + +TEST(ModelInstantiatorTest, consensus) { + carl::VariablePool::getInstance().clear(); + + std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/coin2_2.pm"; + std::string const& formulaAsString = "Pmin=? [F \"finished\"&\"all_coins_equal_1\" ]"; + std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::parseProgram(programFile); + program.checkValidity(); + std::vector<std::shared_ptr<storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaAsString, program); + ASSERT_TRUE(formulas.size()==1); + // Parametric model + typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]); + options.addConstantDefinitionsFromString(program, constantsAsString); + options.preserveFormula(*formulas[0]); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> mdp = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + + storm::utility::ModelInstantiator<storm::models::sparse::Mdp<storm::RationalFunction>, storm::models::sparse::Mdp<double>> modelInstantiator(*mdp); + + std::map<storm::Variable, storm::RationalNumber> valuation; + storm::Variable const& p1 = carl::VariablePool::getInstance().findVariableWithName("p1"); + ASSERT_NE(p1, carl::Variable::NO_VARIABLE); + storm::Variable const& p2 = carl::VariablePool::getInstance().findVariableWithName("p2"); + ASSERT_NE(p2, carl::Variable::NO_VARIABLE); + valuation.insert(std::make_pair(p1,carl::rationalize<storm::RationalNumber>(0.51))); + valuation.insert(std::make_pair(p2,carl::rationalize<storm::RationalNumber>(0.49))); + storm::models::sparse::Mdp<double> const& instantiated(modelInstantiator.instantiate(valuation)); + + ASSERT_EQ(mdp->getTransitionMatrix().getRowGroupIndices(), instantiated.getTransitionMatrix().getRowGroupIndices()); + for(std::size_t rowGroup = 0; rowGroup < mdp->getTransitionMatrix().getRowGroupCount(); ++rowGroup){ + for(std::size_t row = mdp->getTransitionMatrix().getRowGroupIndices()[rowGroup]; row < mdp->getTransitionMatrix().getRowGroupIndices()[rowGroup+1]; ++row){ + auto instantiatedEntry = instantiated.getTransitionMatrix().getRow(row).begin(); + for(auto const& paramEntry : mdp->getTransitionMatrix().getRow(row)){ + EXPECT_EQ(paramEntry.getColumn(), instantiatedEntry->getColumn()); + double evaluatedValue = carl::toDouble(paramEntry.getValue().evaluate(valuation)); + EXPECT_EQ(evaluatedValue, instantiatedEntry->getValue()); + ++instantiatedEntry; + } + EXPECT_EQ(instantiated.getTransitionMatrix().getRow(row).end(),instantiatedEntry); + } + } + EXPECT_EQ(mdp->getStateLabeling(), instantiated.getStateLabeling()); + EXPECT_EQ(mdp->getOptionalChoiceLabeling(), instantiated.getOptionalChoiceLabeling()); + + storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<double>> modelchecker(instantiated); + std::unique_ptr<storm::modelchecker::CheckResult> chkResult = modelchecker.check(*formulas[0]); + storm::modelchecker::ExplicitQuantitativeCheckResult<double>& quantitativeChkResult = chkResult->asExplicitQuantitativeCheckResult<double>(); + EXPECT_NEAR(0.3526577219, quantitativeChkResult[*instantiated.getInitialStates().begin()], storm::settings::generalSettings().getPrecision()); + +} + +#endif \ No newline at end of file diff --git a/test/functional/utility/brp16_2.pm b/test/functional/utility/brp16_2.pm new file mode 100644 index 000000000..d756a90ec --- /dev/null +++ b/test/functional/utility/brp16_2.pm @@ -0,0 +1,146 @@ +// bounded retransmission protocol [D'AJJL01] +// gxn/dxp 23/05/2001 + +dtmc + +// number of chunks +const int N = 16; +// maximum number of retransmissions +const int MAX = 2; + +// reliability of channels +const double pL; +const double pK; + +// timeouts +const double TOMsg; +const double TOAck; + +module sender + + s : [0..6]; + // 0 idle + // 1 next_frame + // 2 wait_ack + // 3 retransmit + // 4 success + // 5 error + // 6 wait sync + srep : [0..3]; + // 0 bottom + // 1 not ok (nok) + // 2 do not know (dk) + // 3 ok (ok) + nrtr : [0..MAX]; + i : [0..N]; + bs : bool; + s_ab : bool; + fs : bool; + ls : bool; + + // idle + [NewFile] (s=0) -> (s'=1) & (i'=1) & (srep'=0); + // next_frame + [aF] (s=1) -> (s'=2) & (fs'=(i=1)) & (ls'=(i=N)) & (bs'=s_ab) & (nrtr'=0); + // wait_ack + [aB] (s=2) -> (s'=4) & (s_ab'=!s_ab); + [TO_Msg] (s=2) -> (s'=3); + [TO_Ack] (s=2) -> (s'=3); + // retransmit + [aF] (s=3) & (nrtr<MAX) -> (s'=2) & (fs'=(i=1)) & (ls'=(i=N)) & (bs'=s_ab) & (nrtr'=nrtr+1); + [] (s=3) & (nrtr=MAX) & (i<N) -> (s'=5) & (srep'=1); + [] (s=3) & (nrtr=MAX) & (i=N) -> (s'=5) & (srep'=2); + // success + [] (s=4) & (i<N) -> (s'=1) & (i'=i+1); + [] (s=4) & (i=N) -> (s'=0) & (srep'=3); + // error + [SyncWait] (s=5) -> (s'=6); + // wait sync + [SyncWait] (s=6) -> (s'=0) & (s_ab'=false); + +endmodule + +module receiver + + r : [0..5]; + // 0 new_file + // 1 fst_safe + // 2 frame_received + // 3 frame_reported + // 4 idle + // 5 resync + rrep : [0..4]; + // 0 bottom + // 1 fst + // 2 inc + // 3 ok + // 4 nok + fr : bool; + lr : bool; + br : bool; + r_ab : bool; + recv : bool; + + + // new_file + [SyncWait] (r=0) -> (r'=0); + [aG] (r=0) -> (r'=1) & (fr'=fs) & (lr'=ls) & (br'=bs) & (recv'=T); + // fst_safe_frame + [] (r=1) -> (r'=2) & (r_ab'=br); + // frame_received + [] (r=2) & (r_ab=br) & (fr=true) & (lr=false) -> (r'=3) & (rrep'=1); + [] (r=2) & (r_ab=br) & (fr=false) & (lr=false) -> (r'=3) & (rrep'=2); + [] (r=2) & (r_ab=br) & (fr=false) & (lr=true) -> (r'=3) & (rrep'=3); + [aA] (r=2) & !(r_ab=br) -> (r'=4); + // frame_reported + [aA] (r=3) -> (r'=4) & (r_ab'=!r_ab); + // idle + [aG] (r=4) -> (r'=2) & (fr'=fs) & (lr'=ls) & (br'=bs) & (recv'=T); + [SyncWait] (r=4) & (ls=true) -> (r'=5); + [SyncWait] (r=4) & (ls=false) -> (r'=5) & (rrep'=4); + // resync + [SyncWait] (r=5) -> (r'=0) & (rrep'=0); + +endmodule + +// prevents more than one file being sent +module tester + + T : bool; + + [NewFile] (T=false) -> (T'=true); + +endmodule + +module channelK + + k : [0..2]; + + // idle + [aF] (k=0) -> pK : (k'=1) + 1-pK : (k'=2); + // sending + [aG] (k=1) -> (k'=0); + // lost + [TO_Msg] (k=2) -> (k'=0); + +endmodule + +module channelL + + l : [0..2]; + + // idle + [aA] (l=0) -> pL : (l'=1) + 1-pL : (l'=2); + // sending + [aB] (l=1) -> (l'=0); + // lost + [TO_Ack] (l=2) -> (l'=0); + +endmodule + +rewards + [TO_Msg] true : TOMsg; + [TO_Ack] true : TOAck; +endrewards + + diff --git a/test/functional/utility/coin2_2.pm b/test/functional/utility/coin2_2.pm new file mode 100644 index 000000000..3f5358cdd --- /dev/null +++ b/test/functional/utility/coin2_2.pm @@ -0,0 +1,56 @@ +//Randomised Consensus Protocol + +mdp +const double p1; // in [0.2 , 0.8] +const double p2; // in [0.2 , 0.8] + + +const int N=2; +const int K=2; +const int range = 2*(K+1)*N; +const int counter_init = (K+1)*N; +const int left = N; +const int right = 2*(K+1)*N - N; + +// shared coin +global counter : [0..range] init counter_init; + +module process1 + + // program counter + pc1 : [0..3]; + // 0 - flip + // 1 - write + // 2 - check + // 3 - finished + + // local coin + coin1 : [0..1]; + + // flip coin + [] (pc1=0) -> p1 : (coin1'=0) & (pc1'=1) + 1 - p1 : (coin1'=1) & (pc1'=1); + // write tails -1 (reset coin to add regularity) + [] (pc1=1) & (coin1=0) & (counter>0) -> (counter'=counter-1) & (pc1'=2) & (coin1'=0); + // write heads +1 (reset coin to add regularity) + [] (pc1=1) & (coin1=1) & (counter<range) -> (counter'=counter+1) & (pc1'=2) & (coin1'=0); + // check + // decide tails + [] (pc1=2) & (counter<=left) -> (pc1'=3) & (coin1'=0); + // decide heads + [] (pc1=2) & (counter>=right) -> (pc1'=3) & (coin1'=1); + // flip again + [] (pc1=2) & (counter>left) & (counter<right) -> (pc1'=0); + // loop (all loop together when done) + [done] (pc1=3) -> (pc1'=3); + +endmodule + +module process2 = process1[pc1=pc2,coin1=coin2,p1=p2] endmodule +label "finished" = pc1=3 &pc2=3 ; +label "all_coins_equal_1" = coin1=1 &coin2=1 ; +rewards "steps" + true : 1; +endrewards + + + From 5e1e5b55a1a0e54934d5b468a2e4c7c1e979b112 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Thu, 10 Mar 2016 13:06:50 +0100 Subject: [PATCH 23/33] renamed expected time formulas to time formulas Former-commit-id: 50a11fe44679db0014322ae96317f2b8cd650c1a --- src/logic/EventuallyFormula.cpp | 10 +++--- src/logic/EventuallyFormula.h | 4 +-- src/logic/ExpectedTimeOperatorFormula.cpp | 32 ------------------- src/logic/Formula.cpp | 18 +++++------ src/logic/Formula.h | 14 ++++---- src/logic/FormulaContext.h | 2 +- src/logic/FormulaInformationVisitor.cpp | 2 +- src/logic/FormulaInformationVisitor.h | 2 +- src/logic/FormulaVisitor.h | 2 +- src/logic/Formulas.h | 2 +- src/logic/FormulasForwardDeclarations.h | 2 +- src/logic/FragmentChecker.cpp | 10 +++--- src/logic/FragmentChecker.h | 2 +- src/logic/FragmentSpecification.cpp | 22 ++++++------- src/logic/FragmentSpecification.h | 12 +++---- src/logic/TimeOperatorFormula.cpp | 32 +++++++++++++++++++ ...peratorFormula.h => TimeOperatorFormula.h} | 8 ++--- src/modelchecker/AbstractModelChecker.cpp | 24 ++++++++++---- src/modelchecker/AbstractModelChecker.h | 7 ++-- .../SparseMarkovAutomatonCslModelChecker.cpp | 6 ++-- .../SparseMarkovAutomatonCslModelChecker.h | 2 +- .../helper/SparseMarkovAutomatonCslHelper.cpp | 2 +- .../helper/SparseMarkovAutomatonCslHelper.h | 2 +- src/parser/FormulaParser.cpp | 12 +++---- 24 files changed, 121 insertions(+), 110 deletions(-) delete mode 100644 src/logic/ExpectedTimeOperatorFormula.cpp create mode 100644 src/logic/TimeOperatorFormula.cpp rename src/logic/{ExpectedTimeOperatorFormula.h => TimeOperatorFormula.h} (63%) diff --git a/src/logic/EventuallyFormula.cpp b/src/logic/EventuallyFormula.cpp index 67699cfb9..56c9decff 100644 --- a/src/logic/EventuallyFormula.cpp +++ b/src/logic/EventuallyFormula.cpp @@ -7,7 +7,7 @@ namespace storm { namespace logic { EventuallyFormula::EventuallyFormula(std::shared_ptr<Formula const> const& subformula, FormulaContext context) : UnaryPathFormula(subformula), context(context) { - STORM_LOG_THROW(context == FormulaContext::Probability || context == FormulaContext::Reward || context == FormulaContext::ExpectedTime, storm::exceptions::InvalidPropertyException, "Invalid context for formula."); + STORM_LOG_THROW(context == FormulaContext::Probability || context == FormulaContext::Reward || context == FormulaContext::Time, storm::exceptions::InvalidPropertyException, "Invalid context for formula."); } bool EventuallyFormula::isEventuallyFormula() const { @@ -22,8 +22,8 @@ namespace storm { return context == FormulaContext::Reward; } - bool EventuallyFormula::isReachabilityExpectedTimeFormula() const { - return context == FormulaContext::ExpectedTime; + bool EventuallyFormula::isReachabilityTimeFormula() const { + return context == FormulaContext::Time; } bool EventuallyFormula::isProbabilityPathFormula() const { @@ -34,8 +34,8 @@ namespace storm { return this->isReachabilityRewardFormula(); } - bool EventuallyFormula::isExpectedTimePathFormula() const { - return this->isReachabilityExpectedTimeFormula(); + bool EventuallyFormula::isTimePathFormula() const { + return this->isReachabilityTimeFormula(); } boost::any EventuallyFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const { diff --git a/src/logic/EventuallyFormula.h b/src/logic/EventuallyFormula.h index 5cca412a9..f3716fee9 100644 --- a/src/logic/EventuallyFormula.h +++ b/src/logic/EventuallyFormula.h @@ -17,10 +17,10 @@ namespace storm { virtual bool isEventuallyFormula() const override; virtual bool isReachabilityProbabilityFormula() const override; virtual bool isReachabilityRewardFormula() const override; - virtual bool isReachabilityExpectedTimeFormula() const override; + virtual bool isReachabilityTimeFormula() const override; virtual bool isProbabilityPathFormula() const override; virtual bool isRewardPathFormula() const override; - virtual bool isExpectedTimePathFormula() const override; + virtual bool isTimePathFormula() const override; virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override; diff --git a/src/logic/ExpectedTimeOperatorFormula.cpp b/src/logic/ExpectedTimeOperatorFormula.cpp deleted file mode 100644 index fb61b8bbd..000000000 --- a/src/logic/ExpectedTimeOperatorFormula.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "src/logic/ExpectedTimeOperatorFormula.h" - -#include "src/logic/FormulaVisitor.h" - -#include "src/utility/macros.h" -#include "src/exceptions/InvalidPropertyException.h" - -namespace storm { - namespace logic { - ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation) { - STORM_LOG_THROW(this->getMeasureType() == MeasureType::Expectation || this->getMeasureType() == MeasureType::Variance, storm::exceptions::InvalidPropertyException, "Invalid measure type in ET-operator."); - } - - bool ExpectedTimeOperatorFormula::isExpectedTimeOperatorFormula() const { - return true; - } - - boost::any ExpectedTimeOperatorFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const { - return visitor.visit(*this, data); - } - - std::shared_ptr<Formula> ExpectedTimeOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const { - return std::make_shared<ExpectedTimeOperatorFormula>(this->getSubformula().substitute(substitution), this->operatorInformation); - } - - std::ostream& ExpectedTimeOperatorFormula::writeToStream(std::ostream& out) const { - out << "ET"; - OperatorFormula::writeToStream(out); - return out; - } - } -} \ No newline at end of file diff --git a/src/logic/Formula.cpp b/src/logic/Formula.cpp index 3a14b7db8..03ee2793d 100644 --- a/src/logic/Formula.cpp +++ b/src/logic/Formula.cpp @@ -94,7 +94,7 @@ namespace storm { return false; } - bool Formula::isExpectedTimePathFormula() const { + bool Formula::isTimePathFormula() const { return false; } @@ -106,7 +106,7 @@ namespace storm { return false; } - bool Formula::isExpectedTimeOperatorFormula() const { + bool Formula::isTimeOperatorFormula() const { return false; } @@ -126,7 +126,7 @@ namespace storm { return false; } - bool Formula::isReachabilityExpectedTimeFormula() const { + bool Formula::isReachabilityTimeFormula() const { return false; } @@ -276,11 +276,11 @@ namespace storm { return dynamic_cast<EventuallyFormula const&>(*this); } - EventuallyFormula& Formula::asReachabilityExpectedTimeFormula() { + EventuallyFormula& Formula::asReachabilityTimeFormula() { return dynamic_cast<EventuallyFormula&>(*this); } - EventuallyFormula const& Formula::asReachabilityExpectedTimeFormula() const { + EventuallyFormula const& Formula::asReachabilityTimeFormula() const { return dynamic_cast<EventuallyFormula const&>(*this); } @@ -324,12 +324,12 @@ namespace storm { return dynamic_cast<LongRunAverageOperatorFormula const&>(*this); } - ExpectedTimeOperatorFormula& Formula::asExpectedTimeOperatorFormula() { - return dynamic_cast<ExpectedTimeOperatorFormula&>(*this); + TimeOperatorFormula& Formula::asTimeOperatorFormula() { + return dynamic_cast<TimeOperatorFormula&>(*this); } - ExpectedTimeOperatorFormula const& Formula::asExpectedTimeOperatorFormula() const { - return dynamic_cast<ExpectedTimeOperatorFormula const&>(*this); + TimeOperatorFormula const& Formula::asTimeOperatorFormula() const { + return dynamic_cast<TimeOperatorFormula const&>(*this); } CumulativeRewardFormula& Formula::asCumulativeRewardFormula() { diff --git a/src/logic/Formula.h b/src/logic/Formula.h index f7916f400..85ee131f7 100644 --- a/src/logic/Formula.h +++ b/src/logic/Formula.h @@ -42,7 +42,7 @@ namespace storm { virtual bool isProbabilityPathFormula() const; virtual bool isRewardPathFormula() const; - virtual bool isExpectedTimePathFormula() const; + virtual bool isTimePathFormula() const; virtual bool isBinaryBooleanStateFormula() const; virtual bool isUnaryBooleanStateFormula() const; @@ -50,7 +50,7 @@ namespace storm { // Operator formulas. virtual bool isOperatorFormula() const; virtual bool isLongRunAverageOperatorFormula() const; - virtual bool isExpectedTimeOperatorFormula() const; + virtual bool isTimeOperatorFormula() const; virtual bool isProbabilityOperatorFormula() const; virtual bool isRewardOperatorFormula() const; @@ -76,7 +76,7 @@ namespace storm { virtual bool isLongRunAverageRewardFormula() const; // Expected time formulas. - virtual bool isReachabilityExpectedTimeFormula() const; + virtual bool isReachabilityTimeFormula() const; // Type checks for abstract intermediate classes. virtual bool isBinaryPathFormula() const; @@ -133,8 +133,8 @@ namespace storm { EventuallyFormula& asReachabilityRewardFormula(); EventuallyFormula const& asReachabilityRewardFormula() const; - EventuallyFormula& asReachabilityExpectedTimeFormula(); - EventuallyFormula const& asReachabilityExpectedTimeFormula() const; + EventuallyFormula& asReachabilityTimeFormula(); + EventuallyFormula const& asReachabilityTimeFormula() const; GloballyFormula& asGloballyFormula(); GloballyFormula const& asGloballyFormula() const; @@ -154,8 +154,8 @@ namespace storm { LongRunAverageOperatorFormula& asLongRunAverageOperatorFormula(); LongRunAverageOperatorFormula const& asLongRunAverageOperatorFormula() const; - ExpectedTimeOperatorFormula& asExpectedTimeOperatorFormula(); - ExpectedTimeOperatorFormula const& asExpectedTimeOperatorFormula() const; + TimeOperatorFormula& asTimeOperatorFormula(); + TimeOperatorFormula const& asTimeOperatorFormula() const; CumulativeRewardFormula& asCumulativeRewardFormula(); CumulativeRewardFormula const& asCumulativeRewardFormula() const; diff --git a/src/logic/FormulaContext.h b/src/logic/FormulaContext.h index 41113cb8d..70ab01a3d 100644 --- a/src/logic/FormulaContext.h +++ b/src/logic/FormulaContext.h @@ -4,7 +4,7 @@ namespace storm { namespace logic { - enum class FormulaContext { Undefined, Probability, Reward, LongRunAverage, ExpectedTime }; + enum class FormulaContext { Undefined, Probability, Reward, LongRunAverage, Time }; } } diff --git a/src/logic/FormulaInformationVisitor.cpp b/src/logic/FormulaInformationVisitor.cpp index f8ef57f92..b44045766 100644 --- a/src/logic/FormulaInformationVisitor.cpp +++ b/src/logic/FormulaInformationVisitor.cpp @@ -41,7 +41,7 @@ namespace storm { return f.getSubformula().accept(*this); } - boost::any FormulaInformationVisitor::visit(ExpectedTimeOperatorFormula const& f, boost::any const& data) const { + boost::any FormulaInformationVisitor::visit(TimeOperatorFormula const& f, boost::any const& data) const { return f.getSubformula().accept(*this); } diff --git a/src/logic/FormulaInformationVisitor.h b/src/logic/FormulaInformationVisitor.h index 2e2cc0d6d..8e706cabf 100644 --- a/src/logic/FormulaInformationVisitor.h +++ b/src/logic/FormulaInformationVisitor.h @@ -19,7 +19,7 @@ namespace storm { virtual boost::any visit(ConditionalFormula const& f, boost::any const& data) const override; virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const override; virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const override; - virtual boost::any visit(ExpectedTimeOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const override; virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override; diff --git a/src/logic/FormulaVisitor.h b/src/logic/FormulaVisitor.h index a2e5b1a4f..1208b63a6 100644 --- a/src/logic/FormulaVisitor.h +++ b/src/logic/FormulaVisitor.h @@ -18,7 +18,7 @@ namespace storm { virtual boost::any visit(ConditionalFormula const& f, boost::any const& data) const = 0; virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const = 0; virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const = 0; - virtual boost::any visit(ExpectedTimeOperatorFormula const& f, boost::any const& data) const = 0; + virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const = 0; virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const = 0; virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const = 0; virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const = 0; diff --git a/src/logic/Formulas.h b/src/logic/Formulas.h index a5218eeb8..7183dcb01 100644 --- a/src/logic/Formulas.h +++ b/src/logic/Formulas.h @@ -18,7 +18,7 @@ #include "src/logic/RewardOperatorFormula.h" #include "src/logic/StateFormula.h" #include "src/logic/LongRunAverageOperatorFormula.h" -#include "src/logic/ExpectedTimeOperatorFormula.h" +#include "src/logic/TimeOperatorFormula.h" #include "src/logic/UnaryBooleanStateFormula.h" #include "src/logic/UnaryPathFormula.h" #include "src/logic/UnaryStateFormula.h" diff --git a/src/logic/FormulasForwardDeclarations.h b/src/logic/FormulasForwardDeclarations.h index 13b4c326c..43fcf0ab9 100644 --- a/src/logic/FormulasForwardDeclarations.h +++ b/src/logic/FormulasForwardDeclarations.h @@ -15,7 +15,7 @@ namespace storm { class ConditionalFormula; class CumulativeRewardFormula; class EventuallyFormula; - class ExpectedTimeOperatorFormula; + class TimeOperatorFormula; class GloballyFormula; class InstantaneousRewardFormula; class LongRunAverageOperatorFormula; diff --git a/src/logic/FragmentChecker.cpp b/src/logic/FragmentChecker.cpp index fb400fc5b..50c5d3115 100644 --- a/src/logic/FragmentChecker.cpp +++ b/src/logic/FragmentChecker.cpp @@ -99,18 +99,18 @@ namespace storm { } else if (f.isReachabilityRewardFormula()) { result = result && inherited.getSpecification().areReachabilityRewardFormulasAllowed(); result = result && f.getSubformula().isStateFormula(); - } else if (f.isReachabilityExpectedTimeFormula()) { - result = result && inherited.getSpecification().areReachbilityExpectedTimeFormulasAllowed(); + } else if (f.isReachabilityTimeFormula()) { + result = result && inherited.getSpecification().areReachbilityTimeFormulasAllowed(); result = result && f.getSubformula().isStateFormula(); } result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, data)); return result; } - boost::any FragmentChecker::visit(ExpectedTimeOperatorFormula const& f, boost::any const& data) const { + boost::any FragmentChecker::visit(TimeOperatorFormula const& f, boost::any const& data) const { InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data); - bool result = inherited.getSpecification().areExpectedTimeOperatorsAllowed(); - result = result && f.getSubformula().isExpectedTimePathFormula(); + bool result = inherited.getSpecification().areTimeOperatorsAllowed(); + result = result && f.getSubformula().isTimePathFormula(); result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == MeasureType::Expectation); if (!inherited.getSpecification().areNestedOperatorsAllowed()) { result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false)))); diff --git a/src/logic/FragmentChecker.h b/src/logic/FragmentChecker.h index 3d22390e6..9b0377aba 100644 --- a/src/logic/FragmentChecker.h +++ b/src/logic/FragmentChecker.h @@ -20,7 +20,7 @@ namespace storm { virtual boost::any visit(ConditionalFormula const& f, boost::any const& data) const override; virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const override; virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const override; - virtual boost::any visit(ExpectedTimeOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const override; virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override; diff --git a/src/logic/FragmentSpecification.cpp b/src/logic/FragmentSpecification.cpp index e243562e8..c2e396ec9 100644 --- a/src/logic/FragmentSpecification.cpp +++ b/src/logic/FragmentSpecification.cpp @@ -89,7 +89,7 @@ namespace storm { conditionalProbabilityFormula = false; conditionalRewardFormula = false; - reachabilityExpectedTimeFormula = false; + reachabilityTimeFormula = false; nestedOperators = true; nestedPathFormulas = false; @@ -121,11 +121,11 @@ namespace storm { return *this; } - bool FragmentSpecification::areExpectedTimeOperatorsAllowed() const { + bool FragmentSpecification::areTimeOperatorsAllowed() const { return expectedTimeOperator; } - FragmentSpecification& FragmentSpecification::setExpectedTimeOperatorsAllowed(bool newValue) { + FragmentSpecification& FragmentSpecification::setTimeOperatorsAllowed(bool newValue) { this->expectedTimeOperator = newValue; return *this; } @@ -283,12 +283,12 @@ namespace storm { return *this; } - bool FragmentSpecification::areReachbilityExpectedTimeFormulasAllowed() const { - return reachabilityExpectedTimeFormula; + bool FragmentSpecification::areReachbilityTimeFormulasAllowed() const { + return reachabilityTimeFormula; } - FragmentSpecification& FragmentSpecification::setReachbilityExpectedTimeFormulasAllowed(bool newValue) { - this->reachabilityExpectedTimeFormula = newValue; + FragmentSpecification& FragmentSpecification::setReachbilityTimeFormulasAllowed(bool newValue) { + this->reachabilityTimeFormula = newValue; return *this; } @@ -341,13 +341,13 @@ namespace storm { this->setProbabilityOperatorsAllowed(newValue); this->setRewardOperatorsAllowed(newValue); this->setLongRunAverageOperatorsAllowed(newValue); - this->setExpectedTimeOperatorsAllowed(newValue); + this->setTimeOperatorsAllowed(newValue); return *this; } - FragmentSpecification& FragmentSpecification::setExpectedTimeAllowed(bool newValue) { - this->setExpectedTimeOperatorsAllowed(newValue); - this->setReachbilityExpectedTimeFormulasAllowed(newValue); + FragmentSpecification& FragmentSpecification::setTimeAllowed(bool newValue) { + this->setTimeOperatorsAllowed(newValue); + this->setReachbilityTimeFormulasAllowed(newValue); return *this; } diff --git a/src/logic/FragmentSpecification.h b/src/logic/FragmentSpecification.h index e850fb172..d9ae9e45d 100644 --- a/src/logic/FragmentSpecification.h +++ b/src/logic/FragmentSpecification.h @@ -19,8 +19,8 @@ namespace storm { bool areRewardOperatorsAllowed() const; FragmentSpecification& setRewardOperatorsAllowed(bool newValue); - bool areExpectedTimeOperatorsAllowed() const; - FragmentSpecification& setExpectedTimeOperatorsAllowed(bool newValue); + bool areTimeOperatorsAllowed() const; + FragmentSpecification& setTimeOperatorsAllowed(bool newValue); bool areLongRunAverageOperatorsAllowed() const; FragmentSpecification& setLongRunAverageOperatorsAllowed(bool newValue); @@ -73,8 +73,8 @@ namespace storm { bool areConditionalRewardFormulasFormulasAllowed() const; FragmentSpecification& setConditionalRewardFormulasAllowed(bool newValue); - bool areReachbilityExpectedTimeFormulasAllowed() const; - FragmentSpecification& setReachbilityExpectedTimeFormulasAllowed(bool newValue); + bool areReachbilityTimeFormulasAllowed() const; + FragmentSpecification& setReachbilityTimeFormulasAllowed(bool newValue); bool areNestedOperatorsAllowed() const; FragmentSpecification& setNestedOperatorsAllowed(bool newValue); @@ -95,7 +95,7 @@ namespace storm { FragmentSpecification& setVarianceMeasureTypeAllowed(bool newValue); FragmentSpecification& setOperatorsAllowed(bool newValue); - FragmentSpecification& setExpectedTimeAllowed(bool newValue); + FragmentSpecification& setTimeAllowed(bool newValue); FragmentSpecification& setLongRunAverageProbabilitiesAllowed(bool newValue); private: @@ -125,7 +125,7 @@ namespace storm { bool conditionalProbabilityFormula; bool conditionalRewardFormula; - bool reachabilityExpectedTimeFormula; + bool reachabilityTimeFormula; // Members that indicate certain restrictions. bool nestedOperators; diff --git a/src/logic/TimeOperatorFormula.cpp b/src/logic/TimeOperatorFormula.cpp new file mode 100644 index 000000000..0b77c0f1e --- /dev/null +++ b/src/logic/TimeOperatorFormula.cpp @@ -0,0 +1,32 @@ +#include "src/logic/TimeOperatorFormula.h" + +#include "src/logic/FormulaVisitor.h" + +#include "src/utility/macros.h" +#include "src/exceptions/InvalidPropertyException.h" + +namespace storm { + namespace logic { + TimeOperatorFormula::TimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation) { + STORM_LOG_THROW(this->getMeasureType() == MeasureType::Expectation || this->getMeasureType() == MeasureType::Variance, storm::exceptions::InvalidPropertyException, "Invalid measure type in ET-operator."); + } + + bool TimeOperatorFormula::isTimeOperatorFormula() const { + return true; + } + + boost::any TimeOperatorFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const { + return visitor.visit(*this, data); + } + + std::shared_ptr<Formula> TimeOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const { + return std::make_shared<TimeOperatorFormula>(this->getSubformula().substitute(substitution), this->operatorInformation); + } + + std::ostream& TimeOperatorFormula::writeToStream(std::ostream& out) const { + out << "T"; + OperatorFormula::writeToStream(out); + return out; + } + } +} \ No newline at end of file diff --git a/src/logic/ExpectedTimeOperatorFormula.h b/src/logic/TimeOperatorFormula.h similarity index 63% rename from src/logic/ExpectedTimeOperatorFormula.h rename to src/logic/TimeOperatorFormula.h index a6e7d3fbd..cde1c0d34 100644 --- a/src/logic/ExpectedTimeOperatorFormula.h +++ b/src/logic/TimeOperatorFormula.h @@ -7,15 +7,15 @@ namespace storm { namespace logic { - class ExpectedTimeOperatorFormula : public OperatorFormula { + class TimeOperatorFormula : public OperatorFormula { public: - ExpectedTimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation()); + TimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation()); - virtual ~ExpectedTimeOperatorFormula() { + virtual ~TimeOperatorFormula() { // Intentionally left empty. } - virtual bool isExpectedTimeOperatorFormula() const override; + virtual bool isTimeOperatorFormula() const override; virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override; diff --git a/src/modelchecker/AbstractModelChecker.cpp b/src/modelchecker/AbstractModelChecker.cpp index f79fa373b..e360454a0 100644 --- a/src/modelchecker/AbstractModelChecker.cpp +++ b/src/modelchecker/AbstractModelChecker.cpp @@ -21,6 +21,8 @@ namespace storm { return this->computeProbabilities(checkTask); } else if (formula.isRewardPathFormula()) { return this->computeRewards(checkTask); + } else if (formula.isTimePathFormula()) { + return this->computeTimes(checkTask); } } else if (formula.isConditionalProbabilityFormula()) { return this->computeConditionalProbabilities(checkTask.substituteFormula(formula.asConditionalFormula())); @@ -114,7 +116,15 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } - std::unique_ptr<CheckResult> AbstractModelChecker::computeExpectedTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> AbstractModelChecker::computeTimes(CheckTask<storm::logic::Formula> const& checkTask) { + storm::logic::Formula const& timeFormula = checkTask.getFormula(); + if (timeFormula.isReachabilityTimeFormula()) { + return this->computeReachabilityTimes(checkTask.substituteFormula(timeFormula.asReachabilityTimeFormula())); + } + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + } + + std::unique_ptr<CheckResult> AbstractModelChecker::computeReachabilityTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } @@ -130,8 +140,8 @@ namespace storm { return this->checkProbabilityOperatorFormula(checkTask.substituteFormula(stateFormula.asProbabilityOperatorFormula())); } else if (stateFormula.isRewardOperatorFormula()) { return this->checkRewardOperatorFormula(checkTask.substituteFormula(stateFormula.asRewardOperatorFormula())); - } else if (stateFormula.isExpectedTimeOperatorFormula()) { - return this->checkExpectedTimeOperatorFormula(checkTask.substituteFormula(stateFormula.asExpectedTimeOperatorFormula())); + } else if (stateFormula.isTimeOperatorFormula()) { + return this->checkTimeOperatorFormula(checkTask.substituteFormula(stateFormula.asTimeOperatorFormula())); } else if (stateFormula.isLongRunAverageOperatorFormula()) { return this->checkLongRunAverageOperatorFormula(checkTask.substituteFormula(stateFormula.asLongRunAverageOperatorFormula())); } else if (stateFormula.isAtomicExpressionFormula()) { @@ -203,11 +213,11 @@ namespace storm { } } - std::unique_ptr<CheckResult> AbstractModelChecker::checkExpectedTimeOperatorFormula(CheckTask<storm::logic::ExpectedTimeOperatorFormula> const& checkTask) { - storm::logic::ExpectedTimeOperatorFormula const& stateFormula = checkTask.getFormula(); - STORM_LOG_THROW(stateFormula.getSubformula().isReachabilityExpectedTimeFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid."); + std::unique_ptr<CheckResult> AbstractModelChecker::checkTimeOperatorFormula(CheckTask<storm::logic::TimeOperatorFormula> const& checkTask) { + storm::logic::TimeOperatorFormula const& stateFormula = checkTask.getFormula(); + STORM_LOG_THROW(stateFormula.getSubformula().isReachabilityTimeFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid."); - std::unique_ptr<CheckResult> result = this->computeExpectedTimes(checkTask.substituteFormula(stateFormula.getSubformula().asEventuallyFormula())); + std::unique_ptr<CheckResult> result = this->computeTimes(checkTask.substituteFormula(stateFormula.getSubformula())); if (checkTask.isBoundSet()) { STORM_LOG_THROW(result->isQuantitative(), storm::exceptions::InvalidOperationException, "Unable to perform comparison operation on non-quantitative result."); diff --git a/src/modelchecker/AbstractModelChecker.h b/src/modelchecker/AbstractModelChecker.h index c63f00a3c..5bba5f33e 100644 --- a/src/modelchecker/AbstractModelChecker.h +++ b/src/modelchecker/AbstractModelChecker.h @@ -51,9 +51,10 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask); virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask); - // The methods to compute the long-run average and expected time. + // The methods to compute the long-run average probabilities and timing measures. virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask); - virtual std::unique_ptr<CheckResult> computeExpectedTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeTimes(CheckTask<storm::logic::Formula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeReachabilityTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask); // The methods to check state formulas. virtual std::unique_ptr<CheckResult> checkStateFormula(CheckTask<storm::logic::StateFormula> const& stateFormula); @@ -63,7 +64,7 @@ namespace storm { virtual std::unique_ptr<CheckResult> checkBooleanLiteralFormula(CheckTask<storm::logic::BooleanLiteralFormula> const& checkTask); virtual std::unique_ptr<CheckResult> checkProbabilityOperatorFormula(CheckTask<storm::logic::ProbabilityOperatorFormula> const& checkTask); virtual std::unique_ptr<CheckResult> checkRewardOperatorFormula(CheckTask<storm::logic::RewardOperatorFormula> const& checkTask); - virtual std::unique_ptr<CheckResult> checkExpectedTimeOperatorFormula(CheckTask<storm::logic::ExpectedTimeOperatorFormula> const& checkTask); + virtual std::unique_ptr<CheckResult> checkTimeOperatorFormula(CheckTask<storm::logic::TimeOperatorFormula> const& checkTask); virtual std::unique_ptr<CheckResult> checkLongRunAverageOperatorFormula(CheckTask<storm::logic::LongRunAverageOperatorFormula> const& checkTask); virtual std::unique_ptr<CheckResult> checkUnaryBooleanStateFormula(CheckTask<storm::logic::UnaryBooleanStateFormula> const& checkTask); }; diff --git a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp index 9892eb530..2d89745ce 100644 --- a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp +++ b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp @@ -33,7 +33,7 @@ namespace storm { bool SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::canHandle(CheckTask<storm::logic::Formula> const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); storm::logic::FragmentSpecification fragment = storm::logic::csl().setGloballyFormulasAllowed(false).setNextFormulasAllowed(false).setReachabilityRewardFormulasAllowed(true); - fragment.setExpectedTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true); + fragment.setTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true); return formula.isInFragment(fragment); } @@ -88,14 +88,14 @@ namespace storm { } template<typename SparseMarkovAutomatonModelType> - std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeExpectedTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeReachabilityTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = 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(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute expected times in non-closed Markov automaton."); std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper<ValueType>::computeExpectedTimes(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *minMaxLinearEquationSolverFactory); + std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper<ValueType>::computeTimes(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *minMaxLinearEquationSolverFactory); return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(result))); } diff --git a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h index 4e4f60850..847646282 100644 --- a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h +++ b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h @@ -25,7 +25,7 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeExpectedTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask); private: // An object that is used for retrieving solvers for systems of linear equations that are the result of nondeterministic choices. diff --git a/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index d926917a5..c03b01871 100644 --- a/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -349,7 +349,7 @@ namespace storm { } template <typename ValueType> - std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeExpectedTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) { + std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) { uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount(); std::vector<ValueType> rewardValues(numberOfStates, storm::utility::zero<ValueType>()); storm::utility::vector::setVectorValues(rewardValues, markovianStates, storm::utility::one<ValueType>()); diff --git a/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 5b24fe569..534f1d272 100644 --- a/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -24,7 +24,7 @@ namespace storm { static std::vector<ValueType> computeLongRunAverageProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory); - static std::vector<ValueType> computeExpectedTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory); + static std::vector<ValueType> computeTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory); private: static void computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<ValueType>& markovianNonGoalValues, std::vector<ValueType>& probabilisticNonGoalValues, ValueType delta, uint_fast64_t numberOfSteps, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory); diff --git a/src/parser/FormulaParser.cpp b/src/parser/FormulaParser.cpp index 7a78b797b..2fa666265 100644 --- a/src/parser/FormulaParser.cpp +++ b/src/parser/FormulaParser.cpp @@ -113,7 +113,7 @@ namespace storm { qi::rule<Iterator, storm::logic::MeasureType(), Skipper> measureType; qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> probabilityOperator; qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> rewardOperator; - qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> expectedTimeOperator; + qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> timeOperator; qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> longRunAverageOperator; qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> simpleFormula; @@ -163,7 +163,7 @@ namespace storm { storm::logic::OperatorInformation createOperatorInformation(storm::logic::MeasureType const& measureType, boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const; std::shared_ptr<storm::logic::Formula> createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; std::shared_ptr<storm::logic::Formula> createRewardOperatorFormula(boost::optional<std::string> const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; - std::shared_ptr<storm::logic::Formula> createExpectedTimeOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; + std::shared_ptr<storm::logic::Formula> createTimeOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; std::shared_ptr<storm::logic::Formula> createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula); std::shared_ptr<storm::logic::Formula> createBinaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, std::shared_ptr<storm::logic::Formula> const& rightSubformula, storm::logic::BinaryBooleanStateFormula::OperatorType operatorType); std::shared_ptr<storm::logic::Formula> createUnaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula> const& subformula, boost::optional<storm::logic::UnaryBooleanStateFormula::OperatorType> const& operatorType); @@ -329,8 +329,8 @@ namespace storm { rewardOperator = (qi::lit("R") > -rewardModelName > operatorInformation(storm::logic::MeasureType::Expectation) > qi::lit("[") > rewardPathFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createRewardOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3)]; rewardOperator.name("reward operator"); - expectedTimeOperator = (qi::lit("ET") > operatorInformation(storm::logic::MeasureType::Expectation) > qi::lit("[") > eventuallyFormula(storm::logic::FormulaContext::ExpectedTime) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createExpectedTimeOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; - expectedTimeOperator.name("expected time operator"); + timeOperator = (qi::lit("T") > operatorInformation(storm::logic::MeasureType::Expectation) > qi::lit("[") > eventuallyFormula(storm::logic::FormulaContext::Time) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; + timeOperator.name("time operator"); probabilityOperator = (qi::lit("P") > operatorInformation(storm::logic::MeasureType::Value) > qi::lit("[") > pathFormula(storm::logic::FormulaContext::Probability) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createProbabilityOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; probabilityOperator.name("probability operator"); @@ -491,8 +491,8 @@ namespace storm { return std::shared_ptr<storm::logic::Formula>(new storm::logic::RewardOperatorFormula(subformula, rewardModelName, operatorInformation)); } - std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createExpectedTimeOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { - return std::shared_ptr<storm::logic::Formula>(new storm::logic::ExpectedTimeOperatorFormula(subformula, operatorInformation)); + std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createTimeOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { + return std::shared_ptr<storm::logic::Formula>(new storm::logic::TimeOperatorFormula(subformula, operatorInformation)); } std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) { From 016ab53f423033b10cd0391635f81add60653821 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Thu, 10 Mar 2016 16:59:38 +0100 Subject: [PATCH 24/33] making the logic formulas better Former-commit-id: bd5dd26c51966c2c10405df2fdb1b8a6ee7e2adf --- src/logic/BinaryBooleanStateFormula.cpp | 5 ++++- src/logic/BinaryBooleanStateFormula.h | 2 +- src/logic/BinaryPathFormula.cpp | 8 ++++++++ src/logic/BinaryPathFormula.h | 3 +++ src/logic/ConditionalFormula.cpp | 8 ++++++++ src/logic/ConditionalFormula.h | 3 +++ src/logic/Formula.cpp | 8 ++++++++ src/logic/Formula.h | 4 ++++ src/logic/FragmentChecker.cpp | 6 ++++++ src/logic/FragmentSpecification.cpp | 22 ++++++++++++++++++++++ src/logic/FragmentSpecification.h | 8 ++++++++ src/logic/OperatorFormula.cpp | 8 ++++++++ src/logic/OperatorFormula.h | 3 +++ src/logic/UnaryBooleanStateFormula.cpp | 5 ++++- src/logic/UnaryPathFormula.cpp | 9 +++++++++ src/logic/UnaryPathFormula.h | 3 +++ 16 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/logic/BinaryBooleanStateFormula.cpp b/src/logic/BinaryBooleanStateFormula.cpp index 180ea12c1..d6757e508 100644 --- a/src/logic/BinaryBooleanStateFormula.cpp +++ b/src/logic/BinaryBooleanStateFormula.cpp @@ -2,10 +2,13 @@ #include "src/logic/FormulaVisitor.h" +#include "src/utility/macros.h" +#include "src/exceptions/InvalidPropertyException.h" + namespace storm { namespace logic { BinaryBooleanStateFormula::BinaryBooleanStateFormula(OperatorType operatorType, std::shared_ptr<Formula const> const& leftSubformula, std::shared_ptr<Formula const> const& rightSubformula) : BinaryStateFormula(leftSubformula, rightSubformula), operatorType(operatorType) { - // Intentionally left empty. + STORM_LOG_THROW(this->getLeftSubformula().hasQualitativeResult() && this->getRightSubformula().hasQualitativeResult(), storm::exceptions::InvalidPropertyException, "Boolean formula must have subformulas with qualitative result."); } bool BinaryBooleanStateFormula::isBinaryBooleanStateFormula() const { diff --git a/src/logic/BinaryBooleanStateFormula.h b/src/logic/BinaryBooleanStateFormula.h index 6956e56c6..892d28bc9 100644 --- a/src/logic/BinaryBooleanStateFormula.h +++ b/src/logic/BinaryBooleanStateFormula.h @@ -25,7 +25,7 @@ namespace storm { virtual bool isAnd() const; virtual bool isOr() const; - + virtual std::ostream& writeToStream(std::ostream& out) const override; virtual std::shared_ptr<Formula> substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const override; diff --git a/src/logic/BinaryPathFormula.cpp b/src/logic/BinaryPathFormula.cpp index 4e028d567..40c187013 100644 --- a/src/logic/BinaryPathFormula.cpp +++ b/src/logic/BinaryPathFormula.cpp @@ -32,5 +32,13 @@ namespace storm { this->getLeftSubformula().gatherReferencedRewardModels(referencedRewardModels); this->getRightSubformula().gatherReferencedRewardModels(referencedRewardModels); } + + bool BinaryPathFormula::hasQualitativeResult() const { + return false; + } + + bool BinaryPathFormula::hasQuantitativeResult() const { + return true; + } } } \ No newline at end of file diff --git a/src/logic/BinaryPathFormula.h b/src/logic/BinaryPathFormula.h index fe0526bee..5550bd466 100644 --- a/src/logic/BinaryPathFormula.h +++ b/src/logic/BinaryPathFormula.h @@ -24,6 +24,9 @@ namespace storm { virtual void gatherAtomicLabelFormulas(std::vector<std::shared_ptr<AtomicLabelFormula const>>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set<std::string>& referencedRewardModels) const override; + virtual bool hasQualitativeResult() const override; + virtual bool hasQuantitativeResult() const override; + private: std::shared_ptr<Formula const> leftSubformula; std::shared_ptr<Formula const> rightSubformula; diff --git a/src/logic/ConditionalFormula.cpp b/src/logic/ConditionalFormula.cpp index af3e1d95b..b12b831be 100644 --- a/src/logic/ConditionalFormula.cpp +++ b/src/logic/ConditionalFormula.cpp @@ -49,6 +49,14 @@ namespace storm { this->getConditionFormula().gatherReferencedRewardModels(referencedRewardModels); } + bool ConditionalFormula::hasQualitativeResult() const { + return false; + } + + bool ConditionalFormula::hasQuantitativeResult() const { + return true; + } + std::ostream& ConditionalFormula::writeToStream(std::ostream& out) const { this->getSubformula().writeToStream(out); out << " || "; diff --git a/src/logic/ConditionalFormula.h b/src/logic/ConditionalFormula.h index fc6b61655..66d71ebba 100644 --- a/src/logic/ConditionalFormula.h +++ b/src/logic/ConditionalFormula.h @@ -32,6 +32,9 @@ namespace storm { virtual void gatherAtomicLabelFormulas(std::vector<std::shared_ptr<AtomicLabelFormula const>>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set<std::string>& referencedRewardModels) const override; + virtual bool hasQualitativeResult() const override; + virtual bool hasQuantitativeResult() const override; + private: std::shared_ptr<Formula const> subformula; std::shared_ptr<Formula const> conditionFormula; diff --git a/src/logic/Formula.cpp b/src/logic/Formula.cpp index 03ee2793d..c48548f10 100644 --- a/src/logic/Formula.cpp +++ b/src/logic/Formula.cpp @@ -142,6 +142,14 @@ namespace storm { return false; } + bool Formula::hasQualitativeResult() const { + return true; + } + + bool Formula::hasQuantitativeResult() const { + return false; + } + bool Formula::isInFragment(FragmentSpecification const& fragment) const { FragmentChecker checker; return checker.conformsToSpecification(*this, fragment); diff --git a/src/logic/Formula.h b/src/logic/Formula.h index 85ee131f7..b77ecfb20 100644 --- a/src/logic/Formula.h +++ b/src/logic/Formula.h @@ -84,6 +84,10 @@ namespace storm { virtual bool isUnaryPathFormula() const; virtual bool isUnaryStateFormula() const; + // Accessors for the return type of a formula. + virtual bool hasQualitativeResult() const; + virtual bool hasQuantitativeResult() const; + bool isInFragment(FragmentSpecification const& fragment) const; FormulaInformation info() const; diff --git a/src/logic/FragmentChecker.cpp b/src/logic/FragmentChecker.cpp index 50c5d3115..16e1d721c 100644 --- a/src/logic/FragmentChecker.cpp +++ b/src/logic/FragmentChecker.cpp @@ -110,6 +110,8 @@ namespace storm { boost::any FragmentChecker::visit(TimeOperatorFormula const& f, boost::any const& data) const { InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data); bool result = inherited.getSpecification().areTimeOperatorsAllowed(); + result = result && (!f.hasQualitativeResult() || inherited.getSpecification().areQualitativeOperatorResultsAllowed()); + result = result && (!f.hasQuantitativeResult() || inherited.getSpecification().areQuantitativeOperatorResultsAllowed()); result = result && f.getSubformula().isTimePathFormula(); result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == MeasureType::Expectation); if (!inherited.getSpecification().areNestedOperatorsAllowed()) { @@ -165,6 +167,8 @@ namespace storm { boost::any FragmentChecker::visit(ProbabilityOperatorFormula const& f, boost::any const& data) const { InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data); bool result = inherited.getSpecification().areProbabilityOperatorsAllowed(); + result = result && (!f.hasQualitativeResult() || inherited.getSpecification().areQualitativeOperatorResultsAllowed()); + result = result && (!f.hasQuantitativeResult() || inherited.getSpecification().areQuantitativeOperatorResultsAllowed()); result = result && (f.getSubformula().isProbabilityPathFormula() || f.getSubformula().isConditionalProbabilityFormula()); if (!inherited.getSpecification().areNestedOperatorsAllowed()) { result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false)))); @@ -177,6 +181,8 @@ namespace storm { boost::any FragmentChecker::visit(RewardOperatorFormula const& f, boost::any const& data) const { InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data); bool result = inherited.getSpecification().areRewardOperatorsAllowed(); + result = result && (!f.hasQualitativeResult() || inherited.getSpecification().areQualitativeOperatorResultsAllowed()); + result = result && (!f.hasQuantitativeResult() || inherited.getSpecification().areQuantitativeOperatorResultsAllowed()); result = result && (f.getSubformula().isRewardPathFormula() || f.getSubformula().isConditionalRewardFormula()); result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == MeasureType::Expectation); if (!inherited.getSpecification().areNestedOperatorsAllowed()) { diff --git a/src/logic/FragmentSpecification.cpp b/src/logic/FragmentSpecification.cpp index c2e396ec9..31f2eeee2 100644 --- a/src/logic/FragmentSpecification.cpp +++ b/src/logic/FragmentSpecification.cpp @@ -97,6 +97,9 @@ namespace storm { stepBoundedUntilFormulas = false; timeBoundedUntilFormulas = false; varianceAsMeasureType = false; + + qualitativeOperatorResults = true; + quantitativeOperatorResults = true; } FragmentSpecification FragmentSpecification::copy() const { @@ -364,6 +367,25 @@ namespace storm { this->varianceAsMeasureType = newValue; return *this; } + + bool FragmentSpecification::areQuantitativeOperatorResultsAllowed() const { + return this->quantitativeOperatorResults; + } + + FragmentSpecification& FragmentSpecification::setQuantitativeOperatorResultsAllowed(bool newValue) { + this->quantitativeOperatorResults = newValue; + return *this; + } + + bool FragmentSpecification::areQualitativeOperatorResultsAllowed() const { + return this->qualitativeOperatorResults; + } + + FragmentSpecification& FragmentSpecification::setQualitativeOperatorResultsAllowed(bool newValue) { + this->qualitativeOperatorResults = newValue; + return *this; + } + } } \ No newline at end of file diff --git a/src/logic/FragmentSpecification.h b/src/logic/FragmentSpecification.h index d9ae9e45d..5074187b8 100644 --- a/src/logic/FragmentSpecification.h +++ b/src/logic/FragmentSpecification.h @@ -94,6 +94,12 @@ namespace storm { bool isVarianceMeasureTypeAllowed() const; FragmentSpecification& setVarianceMeasureTypeAllowed(bool newValue); + bool areQuantitativeOperatorResultsAllowed() const; + FragmentSpecification& setQuantitativeOperatorResultsAllowed(bool newValue); + + bool areQualitativeOperatorResultsAllowed() const; + FragmentSpecification& setQualitativeOperatorResultsAllowed(bool newValue); + FragmentSpecification& setOperatorsAllowed(bool newValue); FragmentSpecification& setTimeAllowed(bool newValue); FragmentSpecification& setLongRunAverageProbabilitiesAllowed(bool newValue); @@ -134,6 +140,8 @@ namespace storm { bool stepBoundedUntilFormulas; bool timeBoundedUntilFormulas; bool varianceAsMeasureType; + bool quantitativeOperatorResults; + bool qualitativeOperatorResults; }; // Propositional. diff --git a/src/logic/OperatorFormula.cpp b/src/logic/OperatorFormula.cpp index 97690d7bf..d7f602ebe 100644 --- a/src/logic/OperatorFormula.cpp +++ b/src/logic/OperatorFormula.cpp @@ -69,6 +69,14 @@ namespace storm { return true; } + bool OperatorFormula::hasQualitativeResult() const { + return this->hasBound(); + } + + bool OperatorFormula::hasQuantitativeResult() const { + return !this->hasBound(); + } + std::ostream& OperatorFormula::writeToStream(std::ostream& out) const { out << "[" << this->operatorInformation.measureType << "]"; if (hasOptimalityType()) { diff --git a/src/logic/OperatorFormula.h b/src/logic/OperatorFormula.h index 43c97ea45..3d8de1dcd 100644 --- a/src/logic/OperatorFormula.h +++ b/src/logic/OperatorFormula.h @@ -46,6 +46,9 @@ namespace storm { // Measure-type-related accessors. MeasureType getMeasureType() const; + virtual bool hasQualitativeResult() const override; + virtual bool hasQuantitativeResult() const override; + virtual std::ostream& writeToStream(std::ostream& out) const override; protected: diff --git a/src/logic/UnaryBooleanStateFormula.cpp b/src/logic/UnaryBooleanStateFormula.cpp index 6d4f9ecdd..3983e5b27 100644 --- a/src/logic/UnaryBooleanStateFormula.cpp +++ b/src/logic/UnaryBooleanStateFormula.cpp @@ -2,10 +2,13 @@ #include "src/logic/FormulaVisitor.h" +#include "src/utility/macros.h" +#include "src/exceptions/InvalidPropertyException.h" + namespace storm { namespace logic { UnaryBooleanStateFormula::UnaryBooleanStateFormula(OperatorType operatorType, std::shared_ptr<Formula const> const& subformula) : UnaryStateFormula(subformula), operatorType(operatorType) { - // Intentionally left empty. + STORM_LOG_THROW(this->getSubformula().hasQualitativeResult(), storm::exceptions::InvalidPropertyException, "Boolean formula must have subformulas with qualitative result."); } bool UnaryBooleanStateFormula::isUnaryBooleanStateFormula() const { diff --git a/src/logic/UnaryPathFormula.cpp b/src/logic/UnaryPathFormula.cpp index 3e0cdaebc..415fb4d4c 100644 --- a/src/logic/UnaryPathFormula.cpp +++ b/src/logic/UnaryPathFormula.cpp @@ -25,5 +25,14 @@ namespace storm { void UnaryPathFormula::gatherReferencedRewardModels(std::set<std::string>& referencedRewardModels) const { this->getSubformula().gatherReferencedRewardModels(referencedRewardModels); } + + bool UnaryPathFormula::hasQualitativeResult() const { + return false; + } + + bool UnaryPathFormula::hasQuantitativeResult() const { + return true; + } + } } \ No newline at end of file diff --git a/src/logic/UnaryPathFormula.h b/src/logic/UnaryPathFormula.h index 3ea27d8f5..bc698338c 100644 --- a/src/logic/UnaryPathFormula.h +++ b/src/logic/UnaryPathFormula.h @@ -23,6 +23,9 @@ namespace storm { virtual void gatherAtomicLabelFormulas(std::vector<std::shared_ptr<AtomicLabelFormula const>>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set<std::string>& referencedRewardModels) const override; + virtual bool hasQualitativeResult() const override; + virtual bool hasQuantitativeResult() const override; + private: std::shared_ptr<Formula const> subformula; }; From 39acf2444886c1fd1ccbc1fdde5a388fd759281b Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 11 Mar 2016 11:46:21 +0100 Subject: [PATCH 25/33] fix for weak bisimulation on CTMCs Former-commit-id: 4eee2e09974713d3bf45174f528155b843de399e --- ...ministicModelBisimulationDecomposition.cpp | 22 +++++++++++++++++-- src/storage/bisimulation/Partition.cpp | 4 ++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp b/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp index 4ef7d93b3..e968c98cd 100644 --- a/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp +++ b/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp @@ -203,6 +203,7 @@ namespace storm { template<typename ModelType> void DeterministicModelBisimulationDecomposition<ModelType>::increaseProbabilityToSplitter(storm::storage::sparse::state_type predecessor, bisimulation::Block<BlockDataType> const& predecessorBlock, ValueType const& value) { + STORM_LOG_TRACE("Increasing probability of " << predecessor << " to splitter by " << value << "."); storm::storage::sparse::state_type predecessorPosition = this->partition.getPosition(predecessor); // If the position of the state is to the right of marker1, we have not seen it before. @@ -269,6 +270,12 @@ namespace storm { continue; } + // If we are computing a weak bisimulation on CTMCs and the predecessor block is the splitter, we + // need to ignore it and proceed to the next predecessor. + if (this->options.getType() == BisimulationType::Weak && this->model.getType() == storm::models::ModelType::Ctmc && predecessorBlock == splitter) { + continue; + } + // We keep track of the probability of the predecessor moving to the splitter. increaseProbabilityToSplitter(predecessor, predecessorBlock, predecessorEntry.getValue()); @@ -278,7 +285,10 @@ namespace storm { moveStateToMarker1(predecessor, predecessorBlock); } - insertIntoPredecessorList(predecessorBlock, predecessorBlocks); + // We must not insert the the splitter itself if we are not computing a weak bisimulation on CTMCs. + if (this->options.getType() != BisimulationType::Weak || this->model.getType() != storm::models::ModelType::Ctmc || predecessorBlock != splitter) { + insertIntoPredecessorList(predecessorBlock, predecessorBlocks); + } } } @@ -431,7 +441,7 @@ namespace storm { template<typename ModelType> void DeterministicModelBisimulationDecomposition<ModelType>::refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue) { STORM_LOG_TRACE("Refining partition based on splitter " << splitter.getId()); - + // The outline of the refinement is as follows. // // We iterate over all states of the splitter and determine for each predecessor the state the probability @@ -464,6 +474,12 @@ namespace storm { continue; } + // If we are computing a weak bisimulation on CTMCs and the predecessor block is the splitter, we + // need to ignore it and proceed to the next predecessor. + if (this->options.getType() == BisimulationType::Weak && this->model.getType() == storm::models::ModelType::Ctmc && predecessorBlock == splitter) { + continue; + } + // We keep track of the probability of the predecessor moving to the splitter. increaseProbabilityToSplitter(predecessor, predecessorBlock, predecessorEntry.getValue()); @@ -495,6 +511,8 @@ namespace storm { // Finally, we split the block based on the precomputed probabilities and the chosen bisimulation type. if (this->options.getType() == BisimulationType::Strong || this->model.getType() == storm::models::ModelType::Ctmc) { + // In the case of CTMCs and weak bisimulation, we still call the "splitStrong" method, but we already have + // taken care of not adding the splitter to the predecessor blocks, so this is safe. refinePredecessorBlocksOfSplitterStrong(predecessorBlocks, splitterQueue); } else { // If the splitter is a predecessor of we can use the computed probabilities to update the silent diff --git a/src/storage/bisimulation/Partition.cpp b/src/storage/bisimulation/Partition.cpp index 698eb5cd7..b433b70d0 100644 --- a/src/storage/bisimulation/Partition.cpp +++ b/src/storage/bisimulation/Partition.cpp @@ -211,7 +211,7 @@ namespace storm { template<typename DataType> std::pair<typename std::vector<std::unique_ptr<Block<DataType>>>::iterator, bool> Partition<DataType>::splitBlock(Block<DataType>& block, storm::storage::sparse::state_type position) { STORM_LOG_THROW(position >= block.getBeginIndex() && position <= block.getEndIndex(), storm::exceptions::InvalidArgumentException, "Cannot split block at illegal position."); - STORM_LOG_TRACE("Splitting " << block.getId() << " at position " << position << " (begin was " << block.getBeginIndex() << "."); + STORM_LOG_TRACE("Splitting " << block.getId() << " at position " << position << " (begin was " << block.getBeginIndex() << ")."); // In case one of the resulting blocks would be empty, we simply return the current block and do not create // a new one. @@ -230,7 +230,7 @@ namespace storm { // Update the mapping of the states in the newly created block. this->mapStatesToBlock(**newBlockIt, this->begin(**newBlockIt), this->end(**newBlockIt)); - + return std::make_pair(newBlockIt, true); } From 51402ec853677fa10b6547ff1ea298779e851c04 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 11 Mar 2016 14:30:29 +0100 Subject: [PATCH 26/33] removed measure type and only added measure type to reward/time operators Former-commit-id: 16e19fe34923d85835961a6096490e0fba66c674 --- src/logic/FragmentChecker.cpp | 4 +- src/logic/LongRunAverageOperatorFormula.cpp | 2 +- src/logic/OperatorFormula.cpp | 22 +--------- src/logic/OperatorFormula.h | 14 ++---- src/logic/ProbabilityOperatorFormula.cpp | 2 +- src/logic/RewardMeasureType.cpp | 19 ++++++++ src/logic/RewardMeasureType.h | 16 +++++++ src/logic/RewardOperatorFormula.cpp | 9 +++- src/logic/RewardOperatorFormula.h | 14 +++++- src/logic/TimeOperatorFormula.cpp | 9 +++- src/logic/TimeOperatorFormula.h | 15 ++++++- src/modelchecker/AbstractModelChecker.cpp | 44 +++++++------------ src/modelchecker/AbstractModelChecker.h | 18 ++++---- .../csl/HybridCtmcCslModelChecker.cpp | 6 +-- .../csl/HybridCtmcCslModelChecker.h | 6 +-- .../csl/SparseCtmcCslModelChecker.cpp | 6 +-- .../csl/SparseCtmcCslModelChecker.h | 6 +-- .../SparseMarkovAutomatonCslModelChecker.cpp | 4 +- .../SparseMarkovAutomatonCslModelChecker.h | 4 +- .../prctl/HybridDtmcPrctlModelChecker.cpp | 6 +-- .../prctl/HybridDtmcPrctlModelChecker.h | 6 +-- .../prctl/HybridMdpPrctlModelChecker.cpp | 6 +-- .../prctl/HybridMdpPrctlModelChecker.h | 6 +-- .../prctl/SparseDtmcPrctlModelChecker.cpp | 8 ++-- .../prctl/SparseDtmcPrctlModelChecker.h | 8 ++-- .../prctl/SparseMdpPrctlModelChecker.cpp | 6 +-- .../prctl/SparseMdpPrctlModelChecker.h | 6 +-- .../prctl/SymbolicDtmcPrctlModelChecker.cpp | 6 +-- .../prctl/SymbolicDtmcPrctlModelChecker.h | 6 +-- .../prctl/SymbolicMdpPrctlModelChecker.cpp | 6 +-- .../prctl/SymbolicMdpPrctlModelChecker.h | 6 +-- .../SparseDtmcEliminationModelChecker.cpp | 4 +- .../SparseDtmcEliminationModelChecker.h | 4 +- src/parser/FormulaParser.cpp | 39 ++++++++-------- 34 files changed, 185 insertions(+), 158 deletions(-) create mode 100644 src/logic/RewardMeasureType.cpp create mode 100644 src/logic/RewardMeasureType.h diff --git a/src/logic/FragmentChecker.cpp b/src/logic/FragmentChecker.cpp index 16e1d721c..09bfc31dd 100644 --- a/src/logic/FragmentChecker.cpp +++ b/src/logic/FragmentChecker.cpp @@ -113,7 +113,7 @@ namespace storm { result = result && (!f.hasQualitativeResult() || inherited.getSpecification().areQualitativeOperatorResultsAllowed()); result = result && (!f.hasQuantitativeResult() || inherited.getSpecification().areQuantitativeOperatorResultsAllowed()); result = result && f.getSubformula().isTimePathFormula(); - result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == MeasureType::Expectation); + result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == RewardMeasureType::Expectation); if (!inherited.getSpecification().areNestedOperatorsAllowed()) { result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false)))); } else { @@ -184,7 +184,7 @@ namespace storm { result = result && (!f.hasQualitativeResult() || inherited.getSpecification().areQualitativeOperatorResultsAllowed()); result = result && (!f.hasQuantitativeResult() || inherited.getSpecification().areQuantitativeOperatorResultsAllowed()); result = result && (f.getSubformula().isRewardPathFormula() || f.getSubformula().isConditionalRewardFormula()); - result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == MeasureType::Expectation); + result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == RewardMeasureType::Expectation); if (!inherited.getSpecification().areNestedOperatorsAllowed()) { result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false)))); } else { diff --git a/src/logic/LongRunAverageOperatorFormula.cpp b/src/logic/LongRunAverageOperatorFormula.cpp index fe261224c..f2e253ead 100644 --- a/src/logic/LongRunAverageOperatorFormula.cpp +++ b/src/logic/LongRunAverageOperatorFormula.cpp @@ -8,7 +8,7 @@ namespace storm { namespace logic { LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation) { - STORM_LOG_THROW(this->getMeasureType() == MeasureType::Value, storm::exceptions::InvalidPropertyException, "Invalid measure type in LRA-operator."); + // Intentionally left empty. } bool LongRunAverageOperatorFormula::isLongRunAverageOperatorFormula() const { diff --git a/src/logic/OperatorFormula.cpp b/src/logic/OperatorFormula.cpp index d7f602ebe..4a8e2e215 100644 --- a/src/logic/OperatorFormula.cpp +++ b/src/logic/OperatorFormula.cpp @@ -2,22 +2,7 @@ namespace storm { namespace logic { - std::ostream& operator<<(std::ostream& out, MeasureType const& type) { - switch (type) { - case MeasureType::Value: - out << "val"; - break; - case MeasureType::Expectation: - out << "exp"; - break; - case MeasureType::Variance: - out << "var"; - break; - } - return out; - } - - OperatorInformation::OperatorInformation(MeasureType const& measureType, boost::optional<storm::solver::OptimizationDirection> const& optimizationDirection, boost::optional<Bound<double>> const& bound) : measureType(measureType), optimalityType(optimizationDirection), bound(bound) { + OperatorInformation::OperatorInformation(boost::optional<storm::solver::OptimizationDirection> const& optimizationDirection, boost::optional<Bound<double>> const& bound) : optimalityType(optimizationDirection), bound(bound) { // Intentionally left empty. } @@ -61,10 +46,6 @@ namespace storm { return operatorInformation.optimalityType.get(); } - MeasureType OperatorFormula::getMeasureType() const { - return operatorInformation.measureType; - } - bool OperatorFormula::isOperatorFormula() const { return true; } @@ -78,7 +59,6 @@ namespace storm { } std::ostream& OperatorFormula::writeToStream(std::ostream& out) const { - out << "[" << this->operatorInformation.measureType << "]"; if (hasOptimalityType()) { out << (getOptimalityType() == OptimizationDirection::Minimize ? "min" : "max"); } diff --git a/src/logic/OperatorFormula.h b/src/logic/OperatorFormula.h index 3d8de1dcd..447647b99 100644 --- a/src/logic/OperatorFormula.h +++ b/src/logic/OperatorFormula.h @@ -8,15 +8,10 @@ #include "src/solver/OptimizationDirection.h" namespace storm { - namespace logic { - enum class MeasureType { Value, Expectation, Variance }; - - std::ostream& operator<<(std::ostream& out, MeasureType const& type); - + namespace logic { struct OperatorInformation { - OperatorInformation(MeasureType const& measureType = MeasureType::Value, boost::optional<storm::solver::OptimizationDirection> const& optimizationDirection = boost::none, boost::optional<Bound<double>> const& bound = boost::none); + OperatorInformation(boost::optional<storm::solver::OptimizationDirection> const& optimizationDirection = boost::none, boost::optional<Bound<double>> const& bound = boost::none); - MeasureType measureType; boost::optional<storm::solver::OptimizationDirection> optimalityType; boost::optional<Bound<double>> bound; }; @@ -42,10 +37,7 @@ namespace storm { bool hasOptimalityType() const; storm::solver::OptimizationDirection const& getOptimalityType() const; virtual bool isOperatorFormula() const override; - - // Measure-type-related accessors. - MeasureType getMeasureType() const; - + virtual bool hasQualitativeResult() const override; virtual bool hasQuantitativeResult() const override; diff --git a/src/logic/ProbabilityOperatorFormula.cpp b/src/logic/ProbabilityOperatorFormula.cpp index b3f7a303c..84d6c55d8 100644 --- a/src/logic/ProbabilityOperatorFormula.cpp +++ b/src/logic/ProbabilityOperatorFormula.cpp @@ -8,7 +8,7 @@ namespace storm { namespace logic { ProbabilityOperatorFormula::ProbabilityOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation) { - STORM_LOG_THROW(this->getMeasureType() == MeasureType::Value, storm::exceptions::InvalidPropertyException, "Invalid measure type in P-operator."); + // Intentionally left empty. } bool ProbabilityOperatorFormula::isProbabilityOperatorFormula() const { diff --git a/src/logic/RewardMeasureType.cpp b/src/logic/RewardMeasureType.cpp new file mode 100644 index 000000000..37098d550 --- /dev/null +++ b/src/logic/RewardMeasureType.cpp @@ -0,0 +1,19 @@ +#include "src/logic/RewardMeasureType.h" + +namespace storm { + namespace logic { + + std::ostream& operator<<(std::ostream& out, RewardMeasureType const& type) { + switch (type) { + case RewardMeasureType::Expectation: + out << "exp"; + break; + case RewardMeasureType::Variance: + out << "var"; + break; + } + return out; + } + + } +} \ No newline at end of file diff --git a/src/logic/RewardMeasureType.h b/src/logic/RewardMeasureType.h new file mode 100644 index 000000000..a48697855 --- /dev/null +++ b/src/logic/RewardMeasureType.h @@ -0,0 +1,16 @@ +#ifndef STORM_LOGIC_REWARDMEASURETYPE_H_ +#define STORM_LOGIC_REWARDMEASURETYPE_H_ + +#include <iostream> + +namespace storm { + namespace logic { + + enum class RewardMeasureType { Expectation, Variance }; + + std::ostream& operator<<(std::ostream& out, RewardMeasureType const& type); + + } +} + +#endif /* STORM_LOGIC_REWARDMEASURETYPE_H_ */ \ No newline at end of file diff --git a/src/logic/RewardOperatorFormula.cpp b/src/logic/RewardOperatorFormula.cpp index cb5a6dc80..0d8315939 100644 --- a/src/logic/RewardOperatorFormula.cpp +++ b/src/logic/RewardOperatorFormula.cpp @@ -7,8 +7,8 @@ namespace storm { namespace logic { - RewardOperatorFormula::RewardOperatorFormula(std::shared_ptr<Formula const> const& subformula, boost::optional<std::string> const& rewardModelName, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation), rewardModelName(rewardModelName) { - STORM_LOG_THROW(this->getMeasureType() == MeasureType::Expectation || this->getMeasureType() == MeasureType::Variance, storm::exceptions::InvalidPropertyException, "Invalid measure type in R-operator."); + RewardOperatorFormula::RewardOperatorFormula(std::shared_ptr<Formula const> const& subformula, boost::optional<std::string> const& rewardModelName, OperatorInformation const& operatorInformation, RewardMeasureType rewardMeasureType) : OperatorFormula(subformula, operatorInformation), rewardModelName(rewardModelName), rewardMeasureType(rewardMeasureType) { + // Intentionally left empty. } bool RewardOperatorFormula::isRewardOperatorFormula() const { @@ -44,8 +44,13 @@ namespace storm { return std::make_shared<RewardOperatorFormula>(this->getSubformula().substitute(substitution), this->rewardModelName, this->operatorInformation); } + RewardMeasureType RewardOperatorFormula::getMeasureType() const { + return rewardMeasureType; + } + std::ostream& RewardOperatorFormula::writeToStream(std::ostream& out) const { out << "R"; + out << "[" << rewardMeasureType << "]"; if (this->hasRewardModelName()) { out << "{\"" << this->getRewardModelName() << "\"}"; } diff --git a/src/logic/RewardOperatorFormula.h b/src/logic/RewardOperatorFormula.h index e371ee0b9..300a82e37 100644 --- a/src/logic/RewardOperatorFormula.h +++ b/src/logic/RewardOperatorFormula.h @@ -1,14 +1,14 @@ #ifndef STORM_LOGIC_REWARDOPERATORFORMULA_H_ #define STORM_LOGIC_REWARDOPERATORFORMULA_H_ -#include <set> #include "src/logic/OperatorFormula.h" +#include "src/logic/RewardMeasureType.h" namespace storm { namespace logic { class RewardOperatorFormula : public OperatorFormula { public: - RewardOperatorFormula(std::shared_ptr<Formula const> const& subformula, boost::optional<std::string> const& rewardModelName = boost::none, OperatorInformation const& operatorInformation = OperatorInformation()); + RewardOperatorFormula(std::shared_ptr<Formula const> const& subformula, boost::optional<std::string> const& rewardModelName = boost::none, OperatorInformation const& operatorInformation = OperatorInformation(), RewardMeasureType rewardMeasureType = RewardMeasureType::Expectation); virtual ~RewardOperatorFormula() { // Intentionally left empty. @@ -44,11 +44,21 @@ namespace storm { */ std::string const& getRewardModelName() const; + /*! + * Retrieves the measure type of the operator. + * + * @return The measure type. + */ + RewardMeasureType getMeasureType() const; + virtual std::shared_ptr<Formula> substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const override; private: // The (optional) name of the reward model this property refers to. boost::optional<std::string> rewardModelName; + + // The measure type of the operator. + RewardMeasureType rewardMeasureType; }; } } diff --git a/src/logic/TimeOperatorFormula.cpp b/src/logic/TimeOperatorFormula.cpp index 0b77c0f1e..c50517640 100644 --- a/src/logic/TimeOperatorFormula.cpp +++ b/src/logic/TimeOperatorFormula.cpp @@ -7,8 +7,8 @@ namespace storm { namespace logic { - TimeOperatorFormula::TimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation) { - STORM_LOG_THROW(this->getMeasureType() == MeasureType::Expectation || this->getMeasureType() == MeasureType::Variance, storm::exceptions::InvalidPropertyException, "Invalid measure type in ET-operator."); + TimeOperatorFormula::TimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation, RewardMeasureType rewardMeasureType) : OperatorFormula(subformula, operatorInformation), rewardMeasureType(rewardMeasureType) { + // Intentionally left empty. } bool TimeOperatorFormula::isTimeOperatorFormula() const { @@ -23,8 +23,13 @@ namespace storm { return std::make_shared<TimeOperatorFormula>(this->getSubformula().substitute(substitution), this->operatorInformation); } + RewardMeasureType TimeOperatorFormula::getMeasureType() const { + return rewardMeasureType; + } + std::ostream& TimeOperatorFormula::writeToStream(std::ostream& out) const { out << "T"; + out << "[" << rewardMeasureType << "]"; OperatorFormula::writeToStream(out); return out; } diff --git a/src/logic/TimeOperatorFormula.h b/src/logic/TimeOperatorFormula.h index cde1c0d34..b9f243a4c 100644 --- a/src/logic/TimeOperatorFormula.h +++ b/src/logic/TimeOperatorFormula.h @@ -2,14 +2,14 @@ #define STORM_LOGIC_EXPECTEDTIMEOPERATORFORMULA_H_ #include "src/logic/OperatorFormula.h" - #include "src/logic/FormulaVisitor.h" +#include "src/logic/RewardMeasureType.h" namespace storm { namespace logic { class TimeOperatorFormula : public OperatorFormula { public: - TimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation()); + TimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation(), RewardMeasureType rewardMeasureType = RewardMeasureType::Expectation); virtual ~TimeOperatorFormula() { // Intentionally left empty. @@ -22,6 +22,17 @@ namespace storm { virtual std::shared_ptr<Formula> substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const override; virtual std::ostream& writeToStream(std::ostream& out) const override; + + /*! + * Retrieves the measure type of the operator. + * + * @return The measure type of the operator. + */ + RewardMeasureType getMeasureType() const; + + private: + // The measure type of the operator. + RewardMeasureType rewardMeasureType; }; } } diff --git a/src/modelchecker/AbstractModelChecker.cpp b/src/modelchecker/AbstractModelChecker.cpp index e360454a0..0ad70fd4b 100644 --- a/src/modelchecker/AbstractModelChecker.cpp +++ b/src/modelchecker/AbstractModelChecker.cpp @@ -16,18 +16,6 @@ namespace storm { STORM_LOG_THROW(this->canHandle(formula), storm::exceptions::InvalidArgumentException, "The model checker is not able to check the formula '" << formula << "'."); if (formula.isStateFormula()) { return this->checkStateFormula(checkTask.substituteFormula(formula.asStateFormula())); - } else if (formula.isPathFormula()) { - if (formula.isProbabilityPathFormula()) { - return this->computeProbabilities(checkTask); - } else if (formula.isRewardPathFormula()) { - return this->computeRewards(checkTask); - } else if (formula.isTimePathFormula()) { - return this->computeTimes(checkTask); - } - } else if (formula.isConditionalProbabilityFormula()) { - return this->computeConditionalProbabilities(checkTask.substituteFormula(formula.asConditionalFormula())); - } else if (formula.isConditionalRewardFormula()) { - return this->computeConditionalRewards(checkTask.substituteFormula(formula.asConditionalFormula())); } STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << formula << "' is invalid."); } @@ -76,39 +64,39 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } - std::unique_ptr<CheckResult> AbstractModelChecker::computeRewards(CheckTask<storm::logic::Formula> const& checkTask) { + std::unique_ptr<CheckResult> AbstractModelChecker::computeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::Formula> const& checkTask) { storm::logic::Formula const& rewardFormula = checkTask.getFormula(); if (rewardFormula.isCumulativeRewardFormula()) { - return this->computeCumulativeRewards(checkTask.substituteFormula(rewardFormula.asCumulativeRewardFormula())); + return this->computeCumulativeRewards(rewardMeasureType, checkTask.substituteFormula(rewardFormula.asCumulativeRewardFormula())); } else if (rewardFormula.isInstantaneousRewardFormula()) { - return this->computeInstantaneousRewards(checkTask.substituteFormula(rewardFormula.asInstantaneousRewardFormula())); + return this->computeInstantaneousRewards(rewardMeasureType, checkTask.substituteFormula(rewardFormula.asInstantaneousRewardFormula())); } else if (rewardFormula.isReachabilityRewardFormula()) { - return this->computeReachabilityRewards(checkTask.substituteFormula(rewardFormula.asReachabilityRewardFormula())); + return this->computeReachabilityRewards(rewardMeasureType, checkTask.substituteFormula(rewardFormula.asReachabilityRewardFormula())); } else if (rewardFormula.isLongRunAverageRewardFormula()) { - return this->computeLongRunAverageRewards(checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula())); + return this->computeLongRunAverageRewards(rewardMeasureType, checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula())); } else if (rewardFormula.isConditionalRewardFormula()) { - return this->computeConditionalRewards(checkTask.substituteFormula(rewardFormula.asConditionalFormula())); + return this->computeConditionalRewards(rewardMeasureType, checkTask.substituteFormula(rewardFormula.asConditionalFormula())); } STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << rewardFormula << "' is invalid."); } - std::unique_ptr<CheckResult> AbstractModelChecker::computeConditionalRewards(CheckTask<storm::logic::ConditionalFormula> const& checkTask) { + std::unique_ptr<CheckResult> AbstractModelChecker::computeConditionalRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::ConditionalFormula> const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } - std::unique_ptr<CheckResult> AbstractModelChecker::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> AbstractModelChecker::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } - std::unique_ptr<CheckResult> AbstractModelChecker::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> AbstractModelChecker::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } - std::unique_ptr<CheckResult> AbstractModelChecker::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> AbstractModelChecker::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } - std::unique_ptr<CheckResult> AbstractModelChecker::computeLongRunAverageRewards(CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> AbstractModelChecker::computeLongRunAverageRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } @@ -116,15 +104,15 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } - std::unique_ptr<CheckResult> AbstractModelChecker::computeTimes(CheckTask<storm::logic::Formula> const& checkTask) { + std::unique_ptr<CheckResult> AbstractModelChecker::computeTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::Formula> const& checkTask) { storm::logic::Formula const& timeFormula = checkTask.getFormula(); if (timeFormula.isReachabilityTimeFormula()) { - return this->computeReachabilityTimes(checkTask.substituteFormula(timeFormula.asReachabilityTimeFormula())); + return this->computeReachabilityTimes(rewardMeasureType, checkTask.substituteFormula(timeFormula.asReachabilityTimeFormula())); } STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } - std::unique_ptr<CheckResult> AbstractModelChecker::computeReachabilityTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> AbstractModelChecker::computeReachabilityTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } @@ -203,7 +191,7 @@ namespace storm { std::unique_ptr<CheckResult> AbstractModelChecker::checkRewardOperatorFormula(CheckTask<storm::logic::RewardOperatorFormula> const& checkTask) { storm::logic::RewardOperatorFormula const& stateFormula = checkTask.getFormula(); - std::unique_ptr<CheckResult> result = this->computeRewards(checkTask.substituteFormula(stateFormula.getSubformula())); + std::unique_ptr<CheckResult> result = this->computeRewards(stateFormula.getMeasureType(), checkTask.substituteFormula(stateFormula.getSubformula())); if (checkTask.isBoundSet()) { STORM_LOG_THROW(result->isQuantitative(), storm::exceptions::InvalidOperationException, "Unable to perform comparison operation on non-quantitative result."); @@ -217,7 +205,7 @@ namespace storm { storm::logic::TimeOperatorFormula const& stateFormula = checkTask.getFormula(); STORM_LOG_THROW(stateFormula.getSubformula().isReachabilityTimeFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid."); - std::unique_ptr<CheckResult> result = this->computeTimes(checkTask.substituteFormula(stateFormula.getSubformula())); + std::unique_ptr<CheckResult> result = this->computeTimes(stateFormula.getMeasureType(), checkTask.substituteFormula(stateFormula.getSubformula())); if (checkTask.isBoundSet()) { STORM_LOG_THROW(result->isQuantitative(), storm::exceptions::InvalidOperationException, "Unable to perform comparison operation on non-quantitative result."); diff --git a/src/modelchecker/AbstractModelChecker.h b/src/modelchecker/AbstractModelChecker.h index 5bba5f33e..b6f009197 100644 --- a/src/modelchecker/AbstractModelChecker.h +++ b/src/modelchecker/AbstractModelChecker.h @@ -11,6 +11,8 @@ namespace storm { namespace modelchecker { class CheckResult; + enum class RewardType { Expectation, Variance }; + class AbstractModelChecker { public: virtual ~AbstractModelChecker() { @@ -44,17 +46,17 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask); // The methods to compute the rewards for path formulas. - virtual std::unique_ptr<CheckResult> computeRewards(CheckTask<storm::logic::Formula> const& checkTask); - virtual std::unique_ptr<CheckResult> computeConditionalRewards(CheckTask<storm::logic::ConditionalFormula> const& checkTask); - virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask); - virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask); - virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask); - virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::Formula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeConditionalRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::ConditionalFormula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask); // The methods to compute the long-run average probabilities and timing measures. virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask); - virtual std::unique_ptr<CheckResult> computeTimes(CheckTask<storm::logic::Formula> const& checkTask); - virtual std::unique_ptr<CheckResult> computeReachabilityTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::Formula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeReachabilityTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask); // The methods to check state formulas. virtual std::unique_ptr<CheckResult> checkStateFormula(CheckTask<storm::logic::StateFormula> const& stateFormula); diff --git a/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp b/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp index a08d7a6b1..81bbbd00e 100644 --- a/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp +++ b/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp @@ -56,7 +56,7 @@ namespace storm { } template<storm::dd::DdType DdType, class ValueType> - std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult<DdType> const& subResult = subResultPointer->asSymbolicQualitativeCheckResult<DdType>(); @@ -85,13 +85,13 @@ namespace storm { } template<storm::dd::DdType DdType, class ValueType> - std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); return storm::modelchecker::helper::HybridCtmcCslHelper<DdType, ValueType>::computeInstantaneousRewards(this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getContinuousTimeBound(), *linearEquationSolverFactory); } template<storm::dd::DdType DdType, class ValueType> - std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); return storm::modelchecker::helper::HybridCtmcCslHelper<DdType, ValueType>::computeCumulativeRewards(this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getContinuousTimeBound(), *linearEquationSolverFactory); } diff --git a/src/modelchecker/csl/HybridCtmcCslModelChecker.h b/src/modelchecker/csl/HybridCtmcCslModelChecker.h index d1e26bcb2..5bfe49405 100644 --- a/src/modelchecker/csl/HybridCtmcCslModelChecker.h +++ b/src/modelchecker/csl/HybridCtmcCslModelChecker.h @@ -21,9 +21,9 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(CheckTask<storm::logic::BoundedUntilFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override; protected: diff --git a/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp b/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp index ee545cb27..7a85682df 100644 --- a/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp +++ b/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp @@ -79,21 +79,21 @@ namespace storm { } template <typename SparseCtmcModelType> - std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); std::vector<ValueType> numericResult = storm::modelchecker::helper::SparseCtmcCslHelper<ValueType>::computeInstantaneousRewards(this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getContinuousTimeBound(), *linearEquationSolverFactory); return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult))); } template <typename SparseCtmcModelType> - std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); std::vector<ValueType> numericResult = storm::modelchecker::helper::SparseCtmcCslHelper<ValueType>::computeCumulativeRewards(this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getContinuousTimeBound(), *linearEquationSolverFactory); return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult))); } template <typename SparseCtmcModelType> - std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); diff --git a/src/modelchecker/csl/SparseCtmcCslModelChecker.h b/src/modelchecker/csl/SparseCtmcCslModelChecker.h index 8def83dc7..f6cee6ae4 100644 --- a/src/modelchecker/csl/SparseCtmcCslModelChecker.h +++ b/src/modelchecker/csl/SparseCtmcCslModelChecker.h @@ -24,9 +24,9 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(CheckTask<storm::logic::BoundedUntilFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override; private: diff --git a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp index 2d89745ce..77535cdbe 100644 --- a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp +++ b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp @@ -63,7 +63,7 @@ namespace storm { } template<typename SparseMarkovAutomatonModelType> - std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = 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(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute reachability rewards in non-closed Markov automaton."); @@ -88,7 +88,7 @@ namespace storm { } template<typename SparseMarkovAutomatonModelType> - std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeReachabilityTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeReachabilityTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = 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(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute expected times in non-closed Markov automaton."); diff --git a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h index 847646282..8509d5f17 100644 --- a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h +++ b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h @@ -23,9 +23,9 @@ namespace storm { virtual bool canHandle(CheckTask<storm::logic::Formula> const& checkTask) const override; virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(CheckTask<storm::logic::BoundedUntilFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeReachabilityTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask); + virtual std::unique_ptr<CheckResult> computeReachabilityTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; private: // An object that is used for retrieving solvers for systems of linear equations that are the result of nondeterministic choices. diff --git a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp index 31628f4ed..4f8c38285 100644 --- a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp +++ b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp @@ -79,21 +79,21 @@ namespace storm { } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidArgumentException, "Formula needs to have a discrete time bound."); return storm::modelchecker::helper::HybridDtmcPrctlHelper<DdType, ValueType>::computeCumulativeRewards(this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *this->linearEquationSolverFactory); } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidArgumentException, "Formula needs to have a discrete time bound."); return storm::modelchecker::helper::HybridDtmcPrctlHelper<DdType, ValueType>::computeInstantaneousRewards(this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *this->linearEquationSolverFactory); } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult<DdType> const& subResult = subResultPointer->asSymbolicQualitativeCheckResult<DdType>(); diff --git a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.h b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.h index b723ea699..3489e74e8 100644 --- a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.h +++ b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.h @@ -22,9 +22,9 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override; protected: diff --git a/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp b/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp index f79bbb933..4d4d8f400 100644 --- a/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp +++ b/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp @@ -77,7 +77,7 @@ namespace storm { } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = 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(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); @@ -85,7 +85,7 @@ namespace storm { } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = 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(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); @@ -93,7 +93,7 @@ namespace storm { } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = 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."); std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula()); diff --git a/src/modelchecker/prctl/HybridMdpPrctlModelChecker.h b/src/modelchecker/prctl/HybridMdpPrctlModelChecker.h index ec3ef2955..3fa7f3d13 100644 --- a/src/modelchecker/prctl/HybridMdpPrctlModelChecker.h +++ b/src/modelchecker/prctl/HybridMdpPrctlModelChecker.h @@ -29,9 +29,9 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; protected: storm::models::symbolic::Mdp<DdType, ValueType> const& getModel() const override; diff --git a/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp b/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp index b21d509ec..d110f067d 100644 --- a/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp +++ b/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp @@ -82,7 +82,7 @@ namespace storm { } template<typename SparseDtmcModelType> - std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); std::vector<ValueType> numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper<ValueType>::computeCumulativeRewards(this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *linearEquationSolverFactory); @@ -90,7 +90,7 @@ namespace storm { } template<typename SparseDtmcModelType> - std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); std::vector<ValueType> numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper<ValueType>::computeInstantaneousRewards(this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *linearEquationSolverFactory); @@ -98,7 +98,7 @@ namespace storm { } template<typename SparseDtmcModelType> - std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); @@ -131,7 +131,7 @@ namespace storm { } template<typename SparseDtmcModelType> - std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeConditionalRewards(CheckTask<storm::logic::ConditionalFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeConditionalRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::ConditionalFormula> const& checkTask) { storm::logic::ConditionalFormula const& conditionalFormula = checkTask.getFormula(); STORM_LOG_THROW(conditionalFormula.getSubformula().isReachabilityRewardFormula(), storm::exceptions::InvalidPropertyException, "Illegal conditional probability formula."); STORM_LOG_THROW(conditionalFormula.getConditionFormula().isEventuallyFormula(), storm::exceptions::InvalidPropertyException, "Illegal conditional probability formula."); diff --git a/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h b/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h index bdfbe5509..6b94f6642 100644 --- a/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h +++ b/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h @@ -27,10 +27,10 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeConditionalProbabilities(CheckTask<storm::logic::ConditionalFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeConditionalRewards(CheckTask<storm::logic::ConditionalFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeConditionalRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::ConditionalFormula> const& checkTask) override; private: // An object that is used for retrieving linear equation solvers. diff --git a/src/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp b/src/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp index 614522e01..44a0223a0 100644 --- a/src/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp +++ b/src/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp @@ -109,7 +109,7 @@ namespace storm { } template<typename SparseMdpModelType> - std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidArgumentException, "Formula needs to have a discrete time bound."); @@ -118,7 +118,7 @@ namespace storm { } template<typename SparseMdpModelType> - std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidArgumentException, "Formula needs to have a discrete time bound."); @@ -127,7 +127,7 @@ namespace storm { } template<typename SparseMdpModelType> - std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula()); diff --git a/src/modelchecker/prctl/SparseMdpPrctlModelChecker.h b/src/modelchecker/prctl/SparseMdpPrctlModelChecker.h index b08c9abc5..2f862d631 100644 --- a/src/modelchecker/prctl/SparseMdpPrctlModelChecker.h +++ b/src/modelchecker/prctl/SparseMdpPrctlModelChecker.h @@ -23,9 +23,9 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeConditionalProbabilities(CheckTask<storm::logic::ConditionalFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override; private: diff --git a/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp b/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp index 311ef7590..9612608df 100644 --- a/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp +++ b/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp @@ -80,7 +80,7 @@ namespace storm { } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); storm::dd::Add<DdType> numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper<DdType, ValueType>::computeCumulativeRewards(this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *this->linearEquationSolverFactory); @@ -88,7 +88,7 @@ namespace storm { } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); storm::dd::Add<DdType> numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper<DdType, ValueType>::computeInstantaneousRewards(this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *this->linearEquationSolverFactory); @@ -96,7 +96,7 @@ namespace storm { } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult<DdType> const& subResult = subResultPointer->asSymbolicQualitativeCheckResult<DdType>(); diff --git a/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h b/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h index 3472ee1b0..883af5ba5 100644 --- a/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h +++ b/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h @@ -19,9 +19,9 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; protected: storm::models::symbolic::Dtmc<DdType, ValueType> const& getModel() const override; diff --git a/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp b/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp index d6a3554e3..f9f2ca37b 100644 --- a/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp +++ b/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp @@ -79,7 +79,7 @@ namespace storm { } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); @@ -87,7 +87,7 @@ namespace storm { } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); @@ -95,7 +95,7 @@ namespace storm { } template<storm::dd::DdType DdType, typename ValueType> - std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = 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."); std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula()); diff --git a/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h b/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h index 488971353..83cb17244 100644 --- a/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h +++ b/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h @@ -21,9 +21,9 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; protected: storm::models::symbolic::Mdp<DdType, ValueType> const& getModel() const override; diff --git a/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp b/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp index 7022b92c8..dcde3c480 100644 --- a/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp +++ b/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp @@ -149,7 +149,7 @@ namespace storm { } template<typename SparseDtmcModelType> - std::unique_ptr<CheckResult> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeLongRunAverageRewards(CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeLongRunAverageRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) { // Do some sanity checks to establish some required properties. RewardModelType const& rewardModel = this->getModel().getRewardModel(checkTask.isRewardModelSet() ? checkTask.getRewardModel() : ""); STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::IllegalArgumentException, "Input model does not have a reward model."); @@ -540,7 +540,7 @@ namespace storm { } template<typename SparseDtmcModelType> - std::unique_ptr<CheckResult> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) { + std::unique_ptr<CheckResult> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); // Retrieve the appropriate bitvectors by model checking the subformulas. diff --git a/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h b/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h index 8b86e1dd9..25b4c12d4 100644 --- a/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h +++ b/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h @@ -26,8 +26,8 @@ namespace storm { virtual bool canHandle(CheckTask<storm::logic::Formula> const& checkTask) const override; virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(CheckTask<storm::logic::BoundedUntilFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; - virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeConditionalProbabilities(CheckTask<storm::logic::ConditionalFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override; diff --git a/src/parser/FormulaParser.cpp b/src/parser/FormulaParser.cpp index 2fa666265..91a5cdb4d 100644 --- a/src/parser/FormulaParser.cpp +++ b/src/parser/FormulaParser.cpp @@ -88,17 +88,16 @@ namespace storm { // A parser used for recognizing the optimality operators. optimalityOperatorStruct optimalityOperator_; - struct measureTypeStruct : qi::symbols<char, storm::logic::MeasureType> { - measureTypeStruct() { + struct rewardMeasureTypeStruct : qi::symbols<char, storm::logic::RewardMeasureType> { + rewardMeasureTypeStruct() { add - ("val", storm::logic::MeasureType::Value) - ("exp", storm::logic::MeasureType::Expectation) - ("var", storm::logic::MeasureType::Variance); + ("exp", storm::logic::RewardMeasureType::Expectation) + ("var", storm::logic::RewardMeasureType::Variance); } }; - // A parser used for recognizing the measure types. - measureTypeStruct measureType_; + // A parser used for recognizing the reward measure types. + rewardMeasureTypeStruct rewardMeasureType_; // Parser and manager used for recognizing expressions. storm::parser::ExpressionParser expressionParser; @@ -109,8 +108,8 @@ namespace storm { qi::rule<Iterator, std::vector<std::shared_ptr<storm::logic::Formula>>(), Skipper> start; - qi::rule<Iterator, storm::logic::OperatorInformation(storm::logic::MeasureType), qi::locals<storm::logic::MeasureType, boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::ComparisonType>, boost::optional<double>>, Skipper> operatorInformation; - qi::rule<Iterator, storm::logic::MeasureType(), Skipper> measureType; + qi::rule<Iterator, storm::logic::OperatorInformation(), qi::locals<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::ComparisonType>, boost::optional<double>>, Skipper> operatorInformation; + qi::rule<Iterator, storm::logic::RewardMeasureType(), Skipper> rewardMeasureType; qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> probabilityOperator; qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> rewardOperator; qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> timeOperator; @@ -160,7 +159,7 @@ namespace storm { std::shared_ptr<storm::logic::Formula> createNextFormula(std::shared_ptr<storm::logic::Formula> const& subformula) const; std::shared_ptr<storm::logic::Formula> createUntilFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, boost::optional<boost::variant<std::pair<double, double>, uint_fast64_t>> const& timeBound, std::shared_ptr<storm::logic::Formula> const& rightSubformula); std::shared_ptr<storm::logic::Formula> createConditionalFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, std::shared_ptr<storm::logic::Formula> const& rightSubformula, storm::logic::FormulaContext context) const; - storm::logic::OperatorInformation createOperatorInformation(storm::logic::MeasureType const& measureType, boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const; + storm::logic::OperatorInformation createOperatorInformation(boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const; std::shared_ptr<storm::logic::Formula> createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; std::shared_ptr<storm::logic::Formula> createRewardOperatorFormula(boost::optional<std::string> const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; std::shared_ptr<storm::logic::Formula> createTimeOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; @@ -314,25 +313,25 @@ namespace storm { pathFormula = conditionalFormula(qi::_r1); pathFormula.name("path formula"); - measureType = qi::lit("[") >> measureType_ >> qi::lit("]"); - measureType.name("measure type"); + rewardMeasureType = qi::lit("[") >> rewardMeasureType_ >> qi::lit("]"); + rewardMeasureType.name("reward measure type"); - operatorInformation = qi::eps[qi::_a = qi::_r1] >> (-measureType[qi::_a = qi::_1] >> -optimalityOperator_[qi::_b = qi::_1] >> ((relationalOperator_[qi::_c = qi::_1] > qi::double_[qi::_d = qi::_1]) | (qi::lit("=") > qi::lit("?"))))[qi::_val = phoenix::bind(&FormulaParserGrammar::createOperatorInformation, phoenix::ref(*this), qi::_a, qi::_b, qi::_c, qi::_d)]; + operatorInformation = (-optimalityOperator_[qi::_a = qi::_1] >> ((relationalOperator_[qi::_b = qi::_1] > qi::double_[qi::_c = qi::_1]) | (qi::lit("=") > qi::lit("?"))))[qi::_val = phoenix::bind(&FormulaParserGrammar::createOperatorInformation, phoenix::ref(*this), qi::_a, qi::_b, qi::_c)]; operatorInformation.name("operator information"); - longRunAverageOperator = ((qi::lit("LRA") | qi::lit("S")) > operatorInformation(storm::logic::MeasureType::Value) > qi::lit("[") > stateFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createLongRunAverageOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; + longRunAverageOperator = ((qi::lit("LRA") | qi::lit("S")) > operatorInformation > qi::lit("[") > stateFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createLongRunAverageOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; longRunAverageOperator.name("long-run average operator"); rewardModelName = qi::lit("{\"") > label > qi::lit("\"}"); rewardModelName.name("reward model name"); - rewardOperator = (qi::lit("R") > -rewardModelName > operatorInformation(storm::logic::MeasureType::Expectation) > qi::lit("[") > rewardPathFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createRewardOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3)]; + rewardOperator = (qi::lit("R") > -rewardModelName > operatorInformation > qi::lit("[") > rewardPathFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createRewardOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3)]; rewardOperator.name("reward operator"); - timeOperator = (qi::lit("T") > operatorInformation(storm::logic::MeasureType::Expectation) > qi::lit("[") > eventuallyFormula(storm::logic::FormulaContext::Time) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; + timeOperator = (qi::lit("T") > operatorInformation > qi::lit("[") > eventuallyFormula(storm::logic::FormulaContext::Time) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; timeOperator.name("time operator"); - probabilityOperator = (qi::lit("P") > operatorInformation(storm::logic::MeasureType::Value) > qi::lit("[") > pathFormula(storm::logic::FormulaContext::Probability) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createProbabilityOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; + probabilityOperator = (qi::lit("P") > operatorInformation > qi::lit("[") > pathFormula(storm::logic::FormulaContext::Probability) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createProbabilityOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; probabilityOperator.name("probability operator"); andStateFormula = notStateFormula[qi::_val = qi::_1] >> *(qi::lit("&") >> notStateFormula)[qi::_val = phoenix::bind(&FormulaParserGrammar::createBinaryBooleanStateFormula, phoenix::ref(*this), qi::_val, qi::_1, storm::logic::BinaryBooleanStateFormula::OperatorType::And)]; @@ -475,11 +474,11 @@ namespace storm { return std::shared_ptr<storm::logic::Formula>(new storm::logic::ConditionalFormula(leftSubformula, rightSubformula, context)); } - storm::logic::OperatorInformation FormulaParserGrammar::createOperatorInformation(storm::logic::MeasureType const& measureType, boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const { + storm::logic::OperatorInformation FormulaParserGrammar::createOperatorInformation(boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const { if (comparisonType && threshold) { - return storm::logic::OperatorInformation(measureType, optimizationDirection, storm::logic::Bound<double>(comparisonType.get(), threshold.get())); + return storm::logic::OperatorInformation(optimizationDirection, storm::logic::Bound<double>(comparisonType.get(), threshold.get())); } else { - return storm::logic::OperatorInformation(measureType, optimizationDirection, boost::none); + return storm::logic::OperatorInformation(optimizationDirection, boost::none); } } From 6a99ab9ef9c4f713e8e09f04e57ace39817fc72d Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 11 Mar 2016 14:56:02 +0100 Subject: [PATCH 27/33] expectation/variance now handled in formula parser Former-commit-id: 9dbe09411c4fc9e602cc82613da481ec27be6fd2 --- src/parser/FormulaParser.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/parser/FormulaParser.cpp b/src/parser/FormulaParser.cpp index 91a5cdb4d..dd0137d9a 100644 --- a/src/parser/FormulaParser.cpp +++ b/src/parser/FormulaParser.cpp @@ -161,8 +161,8 @@ namespace storm { std::shared_ptr<storm::logic::Formula> createConditionalFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, std::shared_ptr<storm::logic::Formula> const& rightSubformula, storm::logic::FormulaContext context) const; storm::logic::OperatorInformation createOperatorInformation(boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const; std::shared_ptr<storm::logic::Formula> createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; - std::shared_ptr<storm::logic::Formula> createRewardOperatorFormula(boost::optional<std::string> const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; - std::shared_ptr<storm::logic::Formula> createTimeOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; + std::shared_ptr<storm::logic::Formula> createRewardOperatorFormula(boost::optional<storm::logic::RewardMeasureType> const& rewardMeasureType, boost::optional<std::string> const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; + std::shared_ptr<storm::logic::Formula> createTimeOperatorFormula(boost::optional<storm::logic::RewardMeasureType> const& rewardMeasureType, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const; std::shared_ptr<storm::logic::Formula> createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula); std::shared_ptr<storm::logic::Formula> createBinaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, std::shared_ptr<storm::logic::Formula> const& rightSubformula, storm::logic::BinaryBooleanStateFormula::OperatorType operatorType); std::shared_ptr<storm::logic::Formula> createUnaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula> const& subformula, boost::optional<storm::logic::UnaryBooleanStateFormula::OperatorType> const& operatorType); @@ -325,10 +325,10 @@ namespace storm { rewardModelName = qi::lit("{\"") > label > qi::lit("\"}"); rewardModelName.name("reward model name"); - rewardOperator = (qi::lit("R") > -rewardModelName > operatorInformation > qi::lit("[") > rewardPathFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createRewardOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3)]; + rewardOperator = (qi::lit("R") > -rewardMeasureType > -rewardModelName > operatorInformation > qi::lit("[") > rewardPathFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createRewardOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_4)]; rewardOperator.name("reward operator"); - timeOperator = (qi::lit("T") > operatorInformation > qi::lit("[") > eventuallyFormula(storm::logic::FormulaContext::Time) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; + timeOperator = (qi::lit("T") > -rewardMeasureType > operatorInformation > qi::lit("[") > eventuallyFormula(storm::logic::FormulaContext::Time) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3)]; timeOperator.name("time operator"); probabilityOperator = (qi::lit("P") > operatorInformation > qi::lit("[") > pathFormula(storm::logic::FormulaContext::Probability) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createProbabilityOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)]; @@ -486,12 +486,20 @@ namespace storm { return std::shared_ptr<storm::logic::Formula>(new storm::logic::LongRunAverageOperatorFormula(subformula, operatorInformation)); } - std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createRewardOperatorFormula(boost::optional<std::string> const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { - return std::shared_ptr<storm::logic::Formula>(new storm::logic::RewardOperatorFormula(subformula, rewardModelName, operatorInformation)); + std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createRewardOperatorFormula(boost::optional<storm::logic::RewardMeasureType> const& rewardMeasureType, boost::optional<std::string> const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { + storm::logic::RewardMeasureType measureType = storm::logic::RewardMeasureType::Expectation; + if (rewardMeasureType) { + measureType = rewardMeasureType.get(); + } + return std::shared_ptr<storm::logic::Formula>(new storm::logic::RewardOperatorFormula(subformula, rewardModelName, operatorInformation, measureType)); } - std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createTimeOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { - return std::shared_ptr<storm::logic::Formula>(new storm::logic::TimeOperatorFormula(subformula, operatorInformation)); + std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createTimeOperatorFormula(boost::optional<storm::logic::RewardMeasureType> const& rewardMeasureType, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const { + storm::logic::RewardMeasureType measureType = storm::logic::RewardMeasureType::Expectation; + if (rewardMeasureType) { + measureType = rewardMeasureType.get(); + } + return std::shared_ptr<storm::logic::Formula>(new storm::logic::TimeOperatorFormula(subformula, operatorInformation, measureType)); } std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) { From 4a19d811330920ecbae5151af128fa4980bac8dd Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 11 Mar 2016 16:13:40 +0100 Subject: [PATCH 28/33] fixed a few bugs Former-commit-id: 70d408e6537e6ef637963d7105cd474716979bd5 --- src/logic/RewardOperatorFormula.cpp | 2 +- src/logic/TimeOperatorFormula.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/RewardOperatorFormula.cpp b/src/logic/RewardOperatorFormula.cpp index 0d8315939..5daea4b59 100644 --- a/src/logic/RewardOperatorFormula.cpp +++ b/src/logic/RewardOperatorFormula.cpp @@ -41,7 +41,7 @@ namespace storm { } std::shared_ptr<Formula> RewardOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const { - return std::make_shared<RewardOperatorFormula>(this->getSubformula().substitute(substitution), this->rewardModelName, this->operatorInformation); + return std::make_shared<RewardOperatorFormula>(this->getSubformula().substitute(substitution), this->rewardModelName, this->operatorInformation, this->rewardMeasureType); } RewardMeasureType RewardOperatorFormula::getMeasureType() const { diff --git a/src/logic/TimeOperatorFormula.cpp b/src/logic/TimeOperatorFormula.cpp index c50517640..6a421a1a5 100644 --- a/src/logic/TimeOperatorFormula.cpp +++ b/src/logic/TimeOperatorFormula.cpp @@ -20,7 +20,7 @@ namespace storm { } std::shared_ptr<Formula> TimeOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const { - return std::make_shared<TimeOperatorFormula>(this->getSubformula().substitute(substitution), this->operatorInformation); + return std::make_shared<TimeOperatorFormula>(this->getSubformula().substitute(substitution), this->operatorInformation, this->rewardMeasureType); } RewardMeasureType TimeOperatorFormula::getMeasureType() const { From adb42b3ac08edb72a9ed86a5fa45cf8fdf8a1cb0 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 11 Mar 2016 16:37:59 +0100 Subject: [PATCH 29/33] fixed minor things related to merge Former-commit-id: f428c2808b1db2a0a5ac458118b546554ff6a22a --- .../utility/ModelInstantiatorTest.cpp | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/test/functional/utility/ModelInstantiatorTest.cpp b/test/functional/utility/ModelInstantiatorTest.cpp index af8f5b8d2..fe2ee4a7c 100644 --- a/test/functional/utility/ModelInstantiatorTest.cpp +++ b/test/functional/utility/ModelInstantiatorTest.cpp @@ -17,12 +17,12 @@ #include "src/models/sparse/Dtmc.h" #include "src/models/sparse/Mdp.h" -TEST(ModelInstantiatorTest, Brp_Prob) { +TEST(ModelInstantiatorTest, BrpProb) { carl::VariablePool::getInstance().clear(); - std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm"; - std::string const& formulaAsString = "P=? [F s=5 ]"; - std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + std::string programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm"; + std::string formulaAsString = "P=? [F s=5 ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 // Program and formula storm::prism::Program program = storm::parseProgram(programFile); @@ -33,7 +33,7 @@ TEST(ModelInstantiatorTest, Brp_Prob) { typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]); options.addConstantDefinitionsFromString(program, constantsAsString); options.preserveFormula(*formulas[0]); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>(program, options).translate()->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); storm::utility::ModelInstantiator<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::models::sparse::Dtmc<double>> modelInstantiator(*dtmc); EXPECT_FALSE(dtmc->hasRewardModel()); @@ -141,9 +141,9 @@ TEST(ModelInstantiatorTest, Brp_Prob) { TEST(ModelInstantiatorTest, Brp_Rew) { carl::VariablePool::getInstance().clear(); - std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm"; - std::string const& formulaAsString = "R=? [F ((s=5) | (s=0&srep=3)) ]"; - std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + std::string programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm"; + std::string formulaAsString = "R=? [F ((s=5) | (s=0&srep=3)) ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 // Program and formula storm::prism::Program program = storm::parseProgram(programFile); @@ -154,7 +154,7 @@ TEST(ModelInstantiatorTest, Brp_Rew) { typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]); options.addConstantDefinitionsFromString(program, constantsAsString); options.preserveFormula(*formulas[0]); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>(program, options).translate()->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); storm::utility::ModelInstantiator<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::models::sparse::Dtmc<double>> modelInstantiator(*dtmc); @@ -211,12 +211,12 @@ TEST(ModelInstantiatorTest, Brp_Rew) { } -TEST(ModelInstantiatorTest, consensus) { +TEST(ModelInstantiatorTest, Consensus) { carl::VariablePool::getInstance().clear(); - std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/coin2_2.pm"; - std::string const& formulaAsString = "Pmin=? [F \"finished\"&\"all_coins_equal_1\" ]"; - std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + std::string programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/coin2_2.pm"; + std::string formulaAsString = "Pmin=? [F \"finished\"&\"all_coins_equal_1\" ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 // Program and formula storm::prism::Program program = storm::parseProgram(programFile); @@ -227,7 +227,7 @@ TEST(ModelInstantiatorTest, consensus) { typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]); options.addConstantDefinitionsFromString(program, constantsAsString); options.preserveFormula(*formulas[0]); - std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> mdp = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> mdp = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>(program, options).translate()->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); storm::utility::ModelInstantiator<storm::models::sparse::Mdp<storm::RationalFunction>, storm::models::sparse::Mdp<double>> modelInstantiator(*mdp); @@ -260,7 +260,6 @@ TEST(ModelInstantiatorTest, consensus) { std::unique_ptr<storm::modelchecker::CheckResult> chkResult = modelchecker.check(*formulas[0]); storm::modelchecker::ExplicitQuantitativeCheckResult<double>& quantitativeChkResult = chkResult->asExplicitQuantitativeCheckResult<double>(); EXPECT_NEAR(0.3526577219, quantitativeChkResult[*instantiated.getInitialStates().begin()], storm::settings::generalSettings().getPrecision()); - } #endif \ No newline at end of file From dae55eeb29291e54312636f62e97c16a207747e0 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Wed, 16 Mar 2016 16:12:22 +0100 Subject: [PATCH 30/33] fixed some bugs and enabled markov automaton model checking from cli Former-commit-id: 91b689d81744ca75d6c7fb374ad2ef3aedbe4ce4 --- .../SparseMarkovAutomatonCslModelChecker.cpp | 12 ++++++- .../helper/SparseMarkovAutomatonCslHelper.cpp | 3 +- src/models/sparse/MarkovAutomaton.cpp | 32 ++++++++++++------- src/models/sparse/MarkovAutomaton.h | 5 +++ .../MarkovAutomatonSparseTransitionParser.cpp | 26 +++++++++++++++ src/utility/storm.h | 11 +++++++ 6 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp index 77535cdbe..7cd7e12ac 100644 --- a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp +++ b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp @@ -46,7 +46,17 @@ namespace storm { std::unique_ptr<CheckResult> rightResultPointer = this->check(pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper<ValueType>::computeBoundedUntilProbabilities(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), rightResult.getTruthValuesVector(), pathFormula.getIntervalBounds(), *minMaxLinearEquationSolverFactory); + double lowerBound = 0; + double upperBound = 0; + if (!pathFormula.hasDiscreteTimeBound()) { + std::pair<double, double> const& intervalBounds = pathFormula.getIntervalBounds(); + lowerBound = intervalBounds.first; + upperBound = intervalBounds.second; + } else { + upperBound = pathFormula.getDiscreteTimeBound(); + } + + std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper<ValueType>::computeBoundedUntilProbabilities(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), rightResult.getTruthValuesVector(), std::make_pair(lowerBound, upperBound), *minMaxLinearEquationSolverFactory); return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(result))); } diff --git a/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index c03b01871..71564b929 100644 --- a/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -32,6 +32,7 @@ namespace storm { template<typename ValueType> void SparseMarkovAutomatonCslHelper<ValueType>::computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<ValueType>& markovianNonGoalValues, std::vector<ValueType>& probabilisticNonGoalValues, ValueType delta, uint_fast64_t numberOfSteps, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) { + // Start by computing four sparse matrices: // * a matrix aMarkovian with all (discretized) transitions from Markovian non-goal states to all Markovian non-goal states. // * a matrix aMarkovianToProbabilistic with all (discretized) transitions from Markovian non-goal states to all probabilistic non-goal states. @@ -116,10 +117,10 @@ namespace storm { storm::utility::vector::addVectors(bProbabilistic, bProbabilisticFixed, bProbabilistic); solver->solveEquationSystem(dir, probabilisticNonGoalValues, bProbabilistic, &multiplicationResultScratchMemory, &aProbabilisticScratchMemory); } - template<typename ValueType> std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) { + uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount(); // 'Unpack' the bounds to make them more easily accessible. diff --git a/src/models/sparse/MarkovAutomaton.cpp b/src/models/sparse/MarkovAutomaton.cpp index 983bda12e..993cc4aa9 100644 --- a/src/models/sparse/MarkovAutomaton.cpp +++ b/src/models/sparse/MarkovAutomaton.cpp @@ -15,7 +15,7 @@ namespace storm { std::vector<ValueType> const& exitRates, std::unordered_map<std::string, RewardModelType> const& rewardModels, boost::optional<std::vector<LabelSet>> const& optionalChoiceLabeling) - : NondeterministicModel<ValueType, RewardModelType>(storm::models::ModelType::MarkovAutomaton, transitionMatrix, stateLabeling, rewardModels, optionalChoiceLabeling), markovianStates(markovianStates), exitRates(exitRates), closed(false) { + : NondeterministicModel<ValueType, RewardModelType>(storm::models::ModelType::MarkovAutomaton, transitionMatrix, stateLabeling, rewardModels, optionalChoiceLabeling), markovianStates(markovianStates), exitRates(exitRates), closed(this->checkIsClosed()) { this->turnRatesToProbabilities(); } @@ -26,7 +26,7 @@ namespace storm { std::vector<ValueType> const& exitRates, std::unordered_map<std::string, RewardModelType>&& rewardModels, boost::optional<std::vector<LabelSet>>&& optionalChoiceLabeling) - : NondeterministicModel<ValueType, RewardModelType>(storm::models::ModelType::MarkovAutomaton, std::move(transitionMatrix), std::move(stateLabeling), std::move(rewardModels), std::move(optionalChoiceLabeling)), markovianStates(markovianStates), exitRates(std::move(exitRates)), closed(false) { + : NondeterministicModel<ValueType, RewardModelType>(storm::models::ModelType::MarkovAutomaton, std::move(transitionMatrix), std::move(stateLabeling), std::move(rewardModels), std::move(optionalChoiceLabeling)), markovianStates(markovianStates), exitRates(std::move(exitRates)), closed(this->checkIsClosed()) { this->turnRatesToProbabilities(); } @@ -97,21 +97,19 @@ namespace storm { // Now copy over all choices that need to be kept. uint_fast64_t currentChoice = 0; for (uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) { - // If the state is a hybrid state, closing it will make it a probabilistic state, so we remove the Markovian marking. - if (this->isHybridState(state)) { - this->markovianStates.set(state, false); - } - // Record the new beginning of choices of this state. newTransitionMatrixBuilder.newRowGroup(currentChoice); - - // If we are currently treating a hybrid state, we need to skip its first choice. + + // If the state is a hybrid state, closing it will make it a probabilistic state, so we remove the Markovian marking. + // Additionally, we need to remember whether we need to skip the first choice of the state when + // we assemble the new transition matrix. + uint_fast64_t offset = 0; if (this->isHybridState(state)) { - // Remove the Markovian state marking. this->markovianStates.set(state, false); + offset = 1; } - for (uint_fast64_t row = this->getTransitionMatrix().getRowGroupIndices()[state] + (this->isHybridState(state) ? 1 : 0); row < this->getTransitionMatrix().getRowGroupIndices()[state + 1]; ++row) { + for (uint_fast64_t row = this->getTransitionMatrix().getRowGroupIndices()[state] + offset; row < this->getTransitionMatrix().getRowGroupIndices()[state + 1]; ++row) { for (auto const& entry : this->getTransitionMatrix().getRow(row)) { newTransitionMatrixBuilder.addNextValue(currentChoice, entry.getColumn(), entry.getValue()); } @@ -216,12 +214,22 @@ namespace storm { template <typename ValueType, typename RewardModelType> void MarkovAutomaton<ValueType, RewardModelType>::turnRatesToProbabilities() { for (auto state : this->markovianStates) { - for (auto& transition : this->getTransitionMatrix().getRowGroup(state)) { + for (auto& transition : this->getTransitionMatrix().getRow(this->getTransitionMatrix().getRowGroupIndices()[state])) { transition.setValue(transition.getValue() / this->exitRates[state]); } } } + template <typename ValueType, typename RewardModelType> + bool MarkovAutomaton<ValueType, RewardModelType>::checkIsClosed() const { + for (auto state : markovianStates) { + if (this->getTransitionMatrix().getRowGroupSize(state) > 1) { + return false; + } + } + return true; + } + template class MarkovAutomaton<double>; // template class MarkovAutomaton<float>; diff --git a/src/models/sparse/MarkovAutomaton.h b/src/models/sparse/MarkovAutomaton.h index 0556ffa9b..3ffb59e70 100644 --- a/src/models/sparse/MarkovAutomaton.h +++ b/src/models/sparse/MarkovAutomaton.h @@ -140,6 +140,11 @@ namespace storm { */ void turnRatesToProbabilities(); + /*! + * Checks whether the automaton is closed by actually looking at the transition information. + */ + bool checkIsClosed() const; + // A bit vector representing the set of Markovian states. storm::storage::BitVector markovianStates; diff --git a/src/parser/MarkovAutomatonSparseTransitionParser.cpp b/src/parser/MarkovAutomatonSparseTransitionParser.cpp index 18d87d314..a49fa3996 100644 --- a/src/parser/MarkovAutomatonSparseTransitionParser.cpp +++ b/src/parser/MarkovAutomatonSparseTransitionParser.cpp @@ -6,6 +6,7 @@ #include "src/exceptions/FileIoException.h" #include "src/parser/MappedFile.h" #include "src/utility/cstring.h" +#include "src/utility/constants.h" #include "src/utility/macros.h" namespace storm { @@ -152,6 +153,16 @@ namespace storm { } } while (!encounteredEOF && !encounteredNewDistribution); } + + // If there are some states with indices that are behind the last source for which no transition was specified, + // we need to reserve some space for introducing self-loops later. + if (!dontFixDeadlocks) { + result.numberOfNonzeroEntries += result.highestStateIndex - lastsource; + result.numberOfChoices += result.highestStateIndex - lastsource; + } else { + STORM_LOG_ERROR("Found deadlock states (e.g. " << lastsource + 1 << ") during parsing. Please fix them or set the appropriate flag."); + throw storm::exceptions::WrongFormatException() << "Found deadlock states (e.g. " << lastsource + 1 << ") during parsing. Please fix them or set the appropriate flag."; + } return result; } @@ -259,6 +270,21 @@ namespace storm { ++currentChoice; } + + // If there are some states with indices that are behind the last source for which no transition was specified, + // we need to insert the self-loops now. Note that we assume all these states to be Markovian. + if (!dontFixDeadlocks) { + for (uint_fast64_t index = lastsource + 1; index <= firstPassResult.highestStateIndex; ++index) { + result.markovianStates.set(index, true); + result.exitRates[index] = storm::utility::one<ValueType>(); + result.transitionMatrixBuilder.newRowGroup(currentChoice); + result.transitionMatrixBuilder.addNextValue(currentChoice, index, storm::utility::one<ValueType>()); + ++currentChoice; + } + } else { + STORM_LOG_ERROR("Found deadlock states (e.g. " << lastsource + 1 << ") during parsing. Please fix them or set the appropriate flag."); + throw storm::exceptions::WrongFormatException() << "Found deadlock states (e.g. " << lastsource + 1 << ") during parsing. Please fix them or set the appropriate flag."; + } return result; } diff --git a/src/utility/storm.h b/src/utility/storm.h index d2963a0f5..1a5cee872 100644 --- a/src/utility/storm.h +++ b/src/utility/storm.h @@ -59,6 +59,7 @@ #include "src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h" #include "src/modelchecker/csl/SparseCtmcCslModelChecker.h" #include "src/modelchecker/csl/HybridCtmcCslModelChecker.h" +#include "src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h" #include "src/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "src/modelchecker/results/SymbolicQualitativeCheckResult.h" @@ -295,6 +296,16 @@ namespace storm { storm::modelchecker::SparseCtmcCslModelChecker<storm::models::sparse::Ctmc<ValueType>> modelchecker(*ctmc); result = modelchecker.check(task); + } else if (model->getType() == storm::models::ModelType::MarkovAutomaton) { + std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma = model->template as<storm::models::sparse::MarkovAutomaton<ValueType>>(); + + // Close the MA, if it is not already closed. + if (!ma->isClosed()) { + ma->close(); + } + + storm::modelchecker::SparseMarkovAutomatonCslModelChecker<storm::models::sparse::MarkovAutomaton<ValueType>> modelchecker(*ma); + result = modelchecker.check(task); } return result; From 4bb4e29e43c0dc866deb1eee32e648d0fb4f47d4 Mon Sep 17 00:00:00 2001 From: TimQu <tim.quatmann@web.de> Date: Fri, 18 Mar 2016 16:47:06 +0100 Subject: [PATCH 31/33] Added a test case where model checking expected rewards on MDPs currently fails Former-commit-id: 35dbe908c8c3cc6a59225832200e28c315803434 --- .../GmmxxMdpPrctlModelCheckerTest.cpp | 33 +++++++++++++++++++ test/functional/modelchecker/tiny_rewards.nm | 17 ++++++++++ 2 files changed, 50 insertions(+) create mode 100644 test/functional/modelchecker/tiny_rewards.nm diff --git a/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp index 93643fd52..22e7d8464 100644 --- a/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp @@ -240,3 +240,36 @@ TEST(GmmxxMdpPrctlModelCheckerTest, SchedulerGeneration) { EXPECT_EQ(0, scheduler2.getChoice(2)); EXPECT_EQ(0, scheduler2.getChoice(3)); } + +TEST(GmmxxMdpPrctlModelCheckerTest, tiny_rewards) { + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/modelchecker/tiny_rewards.nm"); + + // A parser that we use for conveniently constructing the formulas. + storm::parser::FormulaParser formulaParser; + + std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate(); + EXPECT_EQ(3ul, model->getNumberOfStates()); + EXPECT_EQ(4ul, model->getNumberOfTransitions()); + + ASSERT_EQ(model->getType(), storm::models::ModelType::Mdp); + + std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = model->as<storm::models::sparse::Mdp<double>>(); + + EXPECT_EQ(4ul, mdp->getNumberOfChoices()); + + auto solverFactory = std::make_unique<storm::utility::solver::MinMaxLinearEquationSolverFactory<double>>(storm::solver::EquationSolverTypeSelection::Gmmxx); + solverFactory->setPreferredTechnique(storm::solver::MinMaxTechniqueSelection::ValueIteration); + storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<double>> checker(*mdp, std::move(solverFactory)); + + std::shared_ptr<const storm::logic::Formula> formula = formulaParser.parseSingleFormulaFromString("Rmin=? [F \"target\"]"); + + storm::modelchecker::CheckTask<storm::logic::Formula> checkTask(*formula); + + std::unique_ptr<storm::modelchecker::CheckResult> result = checker.check(checkTask); + + ASSERT_TRUE(result->isExplicitQuantitativeCheckResult()); + EXPECT_NEAR(1,result->asExplicitQuantitativeCheckResult<double>().getValueVector()[0], storm::settings::nativeEquationSolverSettings().getPrecision()); + EXPECT_NEAR(1,result->asExplicitQuantitativeCheckResult<double>().getValueVector()[1], storm::settings::nativeEquationSolverSettings().getPrecision()); + EXPECT_NEAR(0,result->asExplicitQuantitativeCheckResult<double>().getValueVector()[2], storm::settings::nativeEquationSolverSettings().getPrecision()); + +} diff --git a/test/functional/modelchecker/tiny_rewards.nm b/test/functional/modelchecker/tiny_rewards.nm new file mode 100644 index 000000000..5119f6306 --- /dev/null +++ b/test/functional/modelchecker/tiny_rewards.nm @@ -0,0 +1,17 @@ +mdp + +module mod1 + +s : [0..2] init 0; +[] s=0 -> true; +[] s=0 -> (s'=1); +[] s=1 -> (s'=2); +[] s=2 -> (s'=2); + +endmodule + +rewards + [] s=1 : 1; +endrewards + +label "target" = s=2; From 67cc067f35035770ebf7596a3faa956b26a5e8eb Mon Sep 17 00:00:00 2001 From: TimQu <tim.quatmann@web.de> Date: Thu, 31 Mar 2016 17:07:52 +0200 Subject: [PATCH 32/33] fixed computeSchedulerProbGreater0E. Previously, it did not enforce that psiStates are actually reached. For instance, it was ok to chose a probability 1 selfloop. Former-commit-id: 518a3b33a96b8550b481d68906bf0161c3328991 --- src/utility/graph.cpp | 44 ++++++++++++++++++++++++++++++++++++++++--- src/utility/graph.h | 19 +++++++++++++++---- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/utility/graph.cpp b/src/utility/graph.cpp index de920ad21..bd10cfd03 100644 --- a/src/utility/graph.cpp +++ b/src/utility/graph.cpp @@ -310,8 +310,46 @@ namespace storm { } template <typename T> - storm::storage::PartialScheduler computeSchedulerProbGreater0E(storm::storage::BitVector const& probGreater0EStates, storm::storage::SparseMatrix<T> const& transitionMatrix) { - return computeSchedulerWithOneSuccessorInStates(probGreater0EStates, transitionMatrix); + storm::storage::PartialScheduler computeSchedulerProbGreater0E(storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional<storm::storage::BitVector> const& rowFilter) { + //Perform backwards DFS from psiStates and find a valid choice for each visited state. + + storm::storage::PartialScheduler result; + std::vector<uint_fast64_t> stack; + storm::storage::BitVector currentStates(psiStates); //the states that are either psiStates or for which we have found a valid choice. + stack.insert(stack.end(), currentStates.begin(), currentStates.end()); + uint_fast64_t currentState = 0; + + while (!stack.empty()) { + currentState = stack.back(); + stack.pop_back(); + + for (typename storm::storage::SparseMatrix<T>::const_iterator predecessorEntryIt = backwardTransitions.begin(currentState), predecessorEntryIte = backwardTransitions.end(currentState); predecessorEntryIt != predecessorEntryIte; ++predecessorEntryIt) { + uint_fast64_t const& predecessor = predecessorEntryIt->getColumn(); + if (phiStates.get(predecessor) && !currentStates.get(predecessor)) { + //The predecessor is a probGreater0E state that has not been considered yet. Let's find the right choice that leads to a state in currentStates. + bool foundValidChoice = false; + for (uint_fast64_t row = transitionMatrix.getRowGroupIndices()[predecessor]; row < transitionMatrix.getRowGroupIndices()[predecessor + 1]; ++row) { + if(rowFilter && !rowFilter->get(row)){ + continue; + } + for (typename storm::storage::SparseMatrix<T>::const_iterator successorEntryIt = transitionMatrix.begin(row), successorEntryIte = transitionMatrix.end(row); successorEntryIt != successorEntryIte; ++successorEntryIt) { + if(currentStates.get(successorEntryIt->getColumn())){ + foundValidChoice = true; + break; + } + } + if(foundValidChoice){ + result.setChoice(predecessor, row - transitionMatrix.getRowGroupIndices()[predecessor]); + currentStates.set(predecessor, true); + stack.push_back(predecessor); + break; + } + } + STORM_LOG_INFO_COND(foundValidChoice, "Could not find a valid choice for ProbGreater0E state " << predecessor << "."); + } + } + } + return result; } template <typename T> @@ -972,7 +1010,7 @@ namespace storm { - template storm::storage::PartialScheduler computeSchedulerProbGreater0E(storm::storage::BitVector const& probGreater0EStates, storm::storage::SparseMatrix<double> const& transitionMatrix); + template storm::storage::PartialScheduler computeSchedulerProbGreater0E(storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional<storm::storage::BitVector> const& rowFilter); template storm::storage::PartialScheduler computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix<double> const& transitionMatrix); diff --git a/src/utility/graph.h b/src/utility/graph.h index 913a8aaab..54e541ac9 100644 --- a/src/utility/graph.h +++ b/src/utility/graph.h @@ -234,13 +234,20 @@ namespace storm { storm::storage::PartialScheduler computeSchedulerWithOneSuccessorInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix<T> const& transitionMatrix); /*! - * Computes a scheduler for the given states that have a scheduler that has a probability greater 0. + * Computes a scheduler for the ProbGreater0E-States such that in the induced system the given psiStates are reachable via phiStates * - * @param probGreater0EStates The states that have a scheduler achieving a probablity greater 0. * @param transitionMatrix The transition matrix of the system. + * @param backwardTransitions The reversed transition relation. + * @param phiStates The set of states satisfying phi. + * @param psiStates The set of states satisfying psi. + * @param rowFilter If given, the returned scheduler will only pick choices such that rowFilter is true for the corresponding matrixrow. + * @return A Scheduler for the ProbGreater0E-States + * + * @note No choice is defined for ProbGreater0E-States if all the probGreater0-choices violate the row filter. + * This also holds for states that only reach psi via such states. */ template <typename T> - storm::storage::PartialScheduler computeSchedulerProbGreater0E(storm::storage::BitVector const& probGreater0EStates, storm::storage::SparseMatrix<T> const& transitionMatrix); + storm::storage::PartialScheduler computeSchedulerProbGreater0E(storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional<storm::storage::BitVector> const& rowFilter = boost::none); /*! * Computes a scheduler for the given states that have a scheduler that has a probability 0. @@ -252,10 +259,14 @@ namespace storm { storm::storage::PartialScheduler computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix<T> const& transitionMatrix); /*! - * Computes a scheduler for the given states that have a scheduler that has a probability 0. + * Computes a scheduler for the given prob1EStates such that in the induced system the given psiStates are reached with probability 1. * * @param prob1EStates The states that have a scheduler achieving probablity 1. * @param transitionMatrix The transition matrix of the system. + * @param backwardTransitions The reversed transition relation. + * @param phiStates The set of states satisfying phi. + * @param psiStates The set of states satisfying psi. + * @return A scheduler for the Prob1E-States */ template <typename T> storm::storage::PartialScheduler computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); From 1136ff0d374ff05fae6f3afabdd8580da475e284 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 1 Apr 2016 14:36:00 +0200 Subject: [PATCH 33/33] fixed a failing test (uninitialized data issue) Former-commit-id: ca0f456ba25e349aaca113677fdc1f8b37f31925 --- src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp | 1 + src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp b/src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp index 9e1b6ef14..98cbcf2ea 100644 --- a/src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp +++ b/src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp @@ -367,6 +367,7 @@ namespace storm { // Now compute reachability probabilities in the transformed model. storm::storage::SparseMatrix<ValueType> const& newTransitionMatrix = transformedModel.transitionMatrix.get(); std::vector<ValueType> conditionalProbabilities = computeUntilProbabilities(newTransitionMatrix, newTransitionMatrix.transpose(), storm::storage::BitVector(newTransitionMatrix.getRowCount(), true), transformedModel.targetStates.get(), qualitative, linearEquationSolverFactory); + storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, conditionalProbabilities); } } diff --git a/src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h b/src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h index 637c30cb5..0be762298 100644 --- a/src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h +++ b/src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h @@ -45,6 +45,10 @@ namespace storm { static std::vector<ValueType> computeReachabilityRewards(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::function<std::vector<ValueType>(uint_fast64_t, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory); struct BaierTransformedModel { + BaierTransformedModel() : noTargetStates(false) { + // Intentionally left empty. + } + storm::storage::BitVector beforeStates; boost::optional<storm::storage::SparseMatrix<ValueType>> transitionMatrix; boost::optional<storm::storage::BitVector> targetStates;