You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

219 lines
10 KiB

  1. /*
  2. * Mdp.h
  3. *
  4. * Created on: 14.01.2013
  5. * Author: Philipp Berger
  6. */
  7. #ifndef STORM_MODELS_MDP_H_
  8. #define STORM_MODELS_MDP_H_
  9. #include <ostream>
  10. #include <iostream>
  11. #include <memory>
  12. #include <cstdlib>
  13. #include <algorithm>
  14. #include "AtomicPropositionsLabeling.h"
  15. #include "src/storage/SparseMatrix.h"
  16. #include "src/settings/Settings.h"
  17. #include "src/models/AbstractNondeterministicModel.h"
  18. #include "src/utility/matrix.h"
  19. namespace storm {
  20. namespace models {
  21. /*!
  22. * This class represents a Markov Decision Process (MDP) whose states are
  23. * labeled with atomic propositions.
  24. */
  25. template <class T>
  26. class Mdp : public storm::models::AbstractNondeterministicModel<T> {
  27. public:
  28. /*!
  29. * Constructs a MDP object from the given transition probability matrix and the given labeling of the states.
  30. * All values are copied.
  31. *
  32. * @param probabilityMatrix The transition probability relation of the MDP given by a matrix.
  33. * @param stateLabeling The labeling that assigns a set of atomic propositions to each state.
  34. * @param optionalStateRewardVector A vector assigning rewards to states.
  35. * @param optionalTransitionRewardVector A sparse matrix that represents an assignment of rewards to the transitions.
  36. * @param optionalChoiceLabeling A vector that represents the labels associated with each nondeterministic choice of
  37. * a state.
  38. */
  39. Mdp(storm::storage::SparseMatrix<T> const& transitionMatrix,
  40. storm::models::AtomicPropositionsLabeling const& stateLabeling,
  41. boost::optional<std::vector<T>> const& optionalStateRewardVector,
  42. boost::optional<storm::storage::SparseMatrix<T>> const& optionalTransitionRewardMatrix,
  43. boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> const& optionalChoiceLabeling)
  44. : AbstractNondeterministicModel<T>(transitionMatrix, stateLabeling, optionalStateRewardVector, optionalTransitionRewardMatrix, optionalChoiceLabeling) {
  45. if (!this->checkValidityOfProbabilityMatrix()) {
  46. LOG4CPLUS_ERROR(logger, "Probability matrix is invalid.");
  47. throw storm::exceptions::InvalidArgumentException() << "Probability matrix is invalid.";
  48. }
  49. if (this->hasTransitionRewards()) {
  50. if (!this->getTransitionRewardMatrix().isSubmatrixOf(this->getTransitionMatrix())) {
  51. LOG4CPLUS_ERROR(logger, "Transition reward matrix is not a submatrix of the transition matrix, i.e. there are rewards for transitions that do not exist.");
  52. throw storm::exceptions::InvalidArgumentException() << "There are transition rewards for nonexistent transitions.";
  53. }
  54. }
  55. }
  56. /*!
  57. * Constructs a MDP object from the given transition probability matrix and
  58. * the given labeling of the states.
  59. * All values are moved.
  60. * @param probabilityMatrix The transition probability relation of the
  61. * MDP given by a matrix.
  62. * @param stateLabeling The labeling that assigns a set of atomic
  63. * propositions to each state.
  64. */
  65. Mdp(storm::storage::SparseMatrix<T>&& transitionMatrix,
  66. storm::models::AtomicPropositionsLabeling&& stateLabeling,
  67. boost::optional<std::vector<T>>&& optionalStateRewardVector,
  68. boost::optional<storm::storage::SparseMatrix<T>>&& optionalTransitionRewardMatrix,
  69. boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>>&& optionalChoiceLabeling)
  70. // The std::move call must be repeated here because otherwise this calls the copy constructor of the Base Class
  71. : AbstractNondeterministicModel<T>(std::move(transitionMatrix), std::move(stateLabeling), std::move(optionalStateRewardVector), std::move(optionalTransitionRewardMatrix),
  72. std::move(optionalChoiceLabeling)) {
  73. if (!this->checkValidityOfProbabilityMatrix()) {
  74. LOG4CPLUS_ERROR(logger, "Probability matrix is invalid.");
  75. throw storm::exceptions::InvalidArgumentException() << "Probability matrix is invalid.";
  76. }
  77. if (this->hasTransitionRewards()) {
  78. if (!this->getTransitionRewardMatrix().isSubmatrixOf(this->getTransitionMatrix())) {
  79. LOG4CPLUS_ERROR(logger, "Transition reward matrix is not a submatrix of the transition matrix, i.e. there are rewards for transitions that do not exist.");
  80. throw storm::exceptions::InvalidArgumentException() << "There are transition rewards for nonexistent transitions.";
  81. }
  82. }
  83. }
  84. /*!
  85. * Copy Constructor. Performs a deep copy of the given MDP.
  86. * @param mdp A reference to the MDP that is to be copied.
  87. */
  88. Mdp(Mdp<T> const & mdp) : AbstractNondeterministicModel<T>(mdp) {
  89. if (!this->checkValidityOfProbabilityMatrix()) {
  90. LOG4CPLUS_ERROR(logger, "Probability matrix is invalid.");
  91. throw storm::exceptions::InvalidArgumentException() << "Probability matrix is invalid.";
  92. }
  93. }
  94. /*!
  95. * Move Constructor. Performs a move on the given MDP.
  96. * @param mdp A reference to the MDP that is to be moved.
  97. */
  98. Mdp(Mdp<T>&& mdp) : AbstractNondeterministicModel<T>(std::move(mdp)) {
  99. if (!this->checkValidityOfProbabilityMatrix()) {
  100. LOG4CPLUS_ERROR(logger, "Probability matrix is invalid.");
  101. throw storm::exceptions::InvalidArgumentException() << "Probability matrix is invalid.";
  102. }
  103. }
  104. /*!
  105. * Destructor.
  106. */
  107. ~Mdp() {
  108. // Intentionally left empty.
  109. }
  110. storm::models::ModelType getType() const {
  111. return MDP;
  112. }
  113. /*!
  114. * Constructs an MDP by copying the current MDP and restricting the choices of each state to the ones whose label set
  115. * is contained in the given label set.
  116. *
  117. * @param enabledChoiceLabels A set of labels that determines which choices of the original model can be taken
  118. * and which ones need to be ignored.
  119. * @return A restricted version of the current MDP that only uses choice labels from the given set.
  120. */
  121. Mdp<T> restrictChoiceLabels(boost::container::flat_set<uint_fast64_t> const& enabledChoiceLabels) const {
  122. // Only perform this operation if the given model has choice labels.
  123. if (!this->hasChoiceLabeling()) {
  124. throw storm::exceptions::InvalidArgumentException() << "Restriction to label set is impossible for unlabeled model.";
  125. }
  126. std::vector<boost::container::flat_set<uint_fast64_t>> const& choiceLabeling = this->getChoiceLabeling();
  127. storm::storage::SparseMatrixBuilder<T> transitionMatrixBuilder;
  128. std::vector<boost::container::flat_set<uint_fast64_t>> newChoiceLabeling;
  129. // Check for each choice of each state, whether the choice labels are fully contained in the given label set.
  130. uint_fast64_t currentRow = 0;
  131. for(uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) {
  132. bool stateHasValidChoice = false;
  133. for (uint_fast64_t choice = this->getTransitionMatrix().getRowGroupIndices()[state]; choice < this->getTransitionMatrix().getRowGroupIndices()[state + 1]; ++choice) {
  134. bool choiceValid = std::includes(enabledChoiceLabels.begin(), enabledChoiceLabels.end(), choiceLabeling[choice].begin(), choiceLabeling[choice].end());
  135. // If the choice is valid, copy over all its elements.
  136. if (choiceValid) {
  137. if (!stateHasValidChoice) {
  138. transitionMatrixBuilder.newRowGroup(currentRow);
  139. }
  140. stateHasValidChoice = true;
  141. for (auto const& entry : this->getTransitionMatrix().getRow(choice)) {
  142. transitionMatrixBuilder.addNextValue(currentRow, entry.first, entry.second);
  143. }
  144. newChoiceLabeling.emplace_back(choiceLabeling[choice]);
  145. ++currentRow;
  146. }
  147. }
  148. // If no choice of the current state may be taken, we insert a self-loop to the state instead.
  149. if (!stateHasValidChoice) {
  150. transitionMatrixBuilder.newRowGroup(currentRow);
  151. transitionMatrixBuilder.addNextValue(currentRow, state, storm::utility::constantOne<T>());
  152. newChoiceLabeling.emplace_back();
  153. ++currentRow;
  154. }
  155. }
  156. Mdp<T> restrictedMdp(transitionMatrixBuilder.build(), storm::models::AtomicPropositionsLabeling(this->getStateLabeling()), this->hasStateRewards() ? boost::optional<std::vector<T>>(this->getStateRewardVector()) : boost::optional<std::vector<T>>(), this->hasTransitionRewards() ? boost::optional<storm::storage::SparseMatrix<T>>(this->getTransitionRewardMatrix()) : boost::optional<storm::storage::SparseMatrix<T>>(), boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>>(newChoiceLabeling));
  157. return restrictedMdp;
  158. }
  159. /*!
  160. * Calculates a hash over all values contained in this Model.
  161. * @return size_t A Hash Value
  162. */
  163. virtual std::size_t getHash() const override {
  164. return AbstractNondeterministicModel<T>::getHash();
  165. }
  166. virtual std::shared_ptr<AbstractModel<T>> applyScheduler(storm::storage::Scheduler const& scheduler) const override {
  167. storm::storage::SparseMatrix<T> newTransitionMatrix = storm::utility::matrix::applyScheduler(this->getTransitionMatrix(), scheduler);
  168. return std::shared_ptr<AbstractModel<T>>(new Mdp(newTransitionMatrix, this->getStateLabeling(), this->hasStateRewards() ? this->getStateRewardVector() : boost::optional<std::vector<T>>(), this->hasTransitionRewards() ? this->getTransitionRewardMatrix() : boost::optional<storm::storage::SparseMatrix<T>>(), this->hasChoiceLabeling() ? this->getChoiceLabeling() : boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>>()));
  169. }
  170. private:
  171. /*!
  172. * @brief Perform some sanity checks.
  173. *
  174. * Checks probability matrix if all rows sum up to one.
  175. */
  176. bool checkValidityOfProbabilityMatrix() {
  177. // Get the settings object to customize linear solving.
  178. storm::settings::Settings* s = storm::settings::Settings::getInstance();
  179. double precision = s->getOptionByLongName("precision").getArgument(0).getValueAsDouble();
  180. for (uint_fast64_t row = 0; row < this->getTransitionMatrix().getRowCount(); row++) {
  181. T sum = this->getTransitionMatrix().getRowSum(row);
  182. if (sum == 0) continue;
  183. if (std::abs(sum - 1) > precision) {
  184. return false;
  185. }
  186. }
  187. return true;
  188. }
  189. };
  190. } // namespace models
  191. } // namespace storm
  192. #endif /* STORM_MODELS_MDP_H_ */