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.

252 lines
16 KiB

  1. #include "storm/storage/StronglyConnectedComponentDecomposition.h"
  2. #include "storm/models/sparse/Model.h"
  3. #include "storm/models/sparse/StandardRewardModel.h"
  4. #include "storm/adapters/CarlAdapter.h"
  5. namespace storm {
  6. namespace storage {
  7. template <typename ValueType>
  8. StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition() : Decomposition() {
  9. // Intentionally left empty.
  10. }
  11. template <typename ValueType>
  12. template <typename RewardModelType>
  13. StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<ValueType, RewardModelType> const& model, bool dropNaiveSccs, bool onlyBottomSccs) : Decomposition() {
  14. performSccDecomposition(model, dropNaiveSccs, onlyBottomSccs);
  15. }
  16. template <typename ValueType>
  17. template <typename RewardModelType>
  18. StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<ValueType, RewardModelType> const& model, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs) {
  19. storm::storage::BitVector subsystem(model.getNumberOfStates(), block.begin(), block.end());
  20. performSccDecomposition(model.getTransitionMatrix(), subsystem, dropNaiveSccs, onlyBottomSccs);
  21. }
  22. template <typename ValueType>
  23. template <typename RewardModelType>
  24. StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<ValueType, RewardModelType> const& model, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) {
  25. performSccDecomposition(model.getTransitionMatrix(), subsystem, dropNaiveSccs, onlyBottomSccs);
  26. }
  27. template <typename ValueType>
  28. StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs) {
  29. storm::storage::BitVector subsystem(transitionMatrix.getRowGroupCount(), block.begin(), block.end());
  30. performSccDecomposition(transitionMatrix, subsystem, dropNaiveSccs, onlyBottomSccs);
  31. }
  32. template <typename ValueType>
  33. StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, bool dropNaiveSccs, bool onlyBottomSccs) {
  34. performSccDecomposition(transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), dropNaiveSccs, onlyBottomSccs);
  35. }
  36. template <typename ValueType>
  37. StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) {
  38. performSccDecomposition(transitionMatrix, subsystem, dropNaiveSccs, onlyBottomSccs);
  39. }
  40. template <typename ValueType>
  41. StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(StronglyConnectedComponentDecomposition const& other) : Decomposition(other) {
  42. // Intentionally left empty.
  43. }
  44. template <typename ValueType>
  45. StronglyConnectedComponentDecomposition<ValueType>& StronglyConnectedComponentDecomposition<ValueType>::operator=(StronglyConnectedComponentDecomposition const& other) {
  46. this->blocks = other.blocks;
  47. return *this;
  48. }
  49. template <typename ValueType>
  50. StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(StronglyConnectedComponentDecomposition&& other) : Decomposition(std::move(other)) {
  51. // Intentionally left empty.
  52. }
  53. template <typename ValueType>
  54. StronglyConnectedComponentDecomposition<ValueType>& StronglyConnectedComponentDecomposition<ValueType>::operator=(StronglyConnectedComponentDecomposition&& other) {
  55. this->blocks = std::move(other.blocks);
  56. return *this;
  57. }
  58. template <typename ValueType>
  59. void StronglyConnectedComponentDecomposition<ValueType>::performSccDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) {
  60. uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount();
  61. // Set up the environment of the algorithm.
  62. // Start with the two stacks it maintains.
  63. std::vector<uint_fast64_t> s;
  64. s.reserve(numberOfStates);
  65. std::vector<uint_fast64_t> p;
  66. p.reserve(numberOfStates);
  67. // We also need to store the preorder numbers of states and which states have been assigned to which SCC.
  68. std::vector<uint_fast64_t> preorderNumbers(numberOfStates);
  69. storm::storage::BitVector hasPreorderNumber(numberOfStates);
  70. storm::storage::BitVector stateHasScc(numberOfStates);
  71. std::vector<uint_fast64_t> stateToSccMapping(numberOfStates);
  72. uint_fast64_t sccCount = 0;
  73. // Finally, we need to keep track of the states with a self-loop to identify naive SCCs.
  74. storm::storage::BitVector statesWithSelfLoop(numberOfStates);
  75. // Start the search for SCCs from every state in the block.
  76. uint_fast64_t currentIndex = 0;
  77. for (auto state : subsystem) {
  78. if (!hasPreorderNumber.get(state)) {
  79. performSccDecompositionGCM(transitionMatrix, state, statesWithSelfLoop, subsystem, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount);
  80. }
  81. }
  82. // After we obtained the state-to-SCC mapping, we build the actual blocks.
  83. this->blocks.resize(sccCount);
  84. for (auto state : subsystem) {
  85. this->blocks[stateToSccMapping[state]].insert(state);
  86. }
  87. // Now flag all trivial SCCs as such.
  88. for (uint_fast64_t sccIndex = 0; sccIndex < sccCount; ++sccIndex) {
  89. if (this->blocks[sccIndex].size() == 1) {
  90. uint_fast64_t onlyState = *this->blocks[sccIndex].begin();
  91. if (!statesWithSelfLoop.get(onlyState)) {
  92. this->blocks[sccIndex].setIsTrivial(true);
  93. }
  94. }
  95. }
  96. // If requested, we need to drop some SCCs.
  97. if (onlyBottomSccs || dropNaiveSccs) {
  98. storm::storage::BitVector blocksToDrop(sccCount);
  99. // If requested, we need to delete all naive SCCs.
  100. if (dropNaiveSccs) {
  101. for (uint_fast64_t sccIndex = 0; sccIndex < sccCount; ++sccIndex) {
  102. if (this->blocks[sccIndex].isTrivial()) {
  103. blocksToDrop.set(sccIndex);
  104. }
  105. }
  106. }
  107. // If requested, we need to drop all non-bottom SCCs.
  108. if (onlyBottomSccs) {
  109. for (uint_fast64_t state = 0; state < numberOfStates; ++state) {
  110. // If the block of the state is already known to be dropped, we don't need to check the transitions.
  111. if (!blocksToDrop.get(stateToSccMapping[state])) {
  112. for (typename storm::storage::SparseMatrix<ValueType>::const_iterator successorIt = transitionMatrix.getRowGroup(state).begin(), successorIte = transitionMatrix.getRowGroup(state).end(); successorIt != successorIte; ++successorIt) {
  113. if (subsystem.get(successorIt->getColumn()) && stateToSccMapping[state] != stateToSccMapping[successorIt->getColumn()]) {
  114. blocksToDrop.set(stateToSccMapping[state]);
  115. break;
  116. }
  117. }
  118. }
  119. }
  120. }
  121. // Create the new set of blocks by moving all the blocks we need to keep into it.
  122. std::vector<block_type> newBlocks((~blocksToDrop).getNumberOfSetBits());
  123. uint_fast64_t currentBlock = 0;
  124. for (uint_fast64_t blockIndex = 0; blockIndex < this->blocks.size(); ++blockIndex) {
  125. if (!blocksToDrop.get(blockIndex)) {
  126. newBlocks[currentBlock] = std::move(this->blocks[blockIndex]);
  127. ++currentBlock;
  128. }
  129. }
  130. // Now set this new set of blocks as the result of the decomposition.
  131. this->blocks = std::move(newBlocks);
  132. }
  133. }
  134. template <typename ValueType>
  135. template <typename RewardModelType>
  136. void StronglyConnectedComponentDecomposition<ValueType>::performSccDecomposition(storm::models::sparse::Model<ValueType, RewardModelType> const& model, bool dropNaiveSccs, bool onlyBottomSccs) {
  137. // Prepare a block that contains all states for a call to the other overload of this function.
  138. storm::storage::BitVector fullSystem(model.getNumberOfStates(), true);
  139. // Call the overloaded function.
  140. performSccDecomposition(model.getTransitionMatrix(), fullSystem, dropNaiveSccs, onlyBottomSccs);
  141. }
  142. template <typename ValueType>
  143. void StronglyConnectedComponentDecomposition<ValueType>::performSccDecompositionGCM(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const& subsystem, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector<uint_fast64_t>& preorderNumbers, std::vector<uint_fast64_t>& s, std::vector<uint_fast64_t>& p, storm::storage::BitVector& stateHasScc, std::vector<uint_fast64_t>& stateToSccMapping, uint_fast64_t& sccCount) {
  144. // Prepare the stack used for turning the recursive procedure into an iterative one.
  145. std::vector<uint_fast64_t> recursionStateStack;
  146. recursionStateStack.reserve(transitionMatrix.getRowGroupCount());
  147. recursionStateStack.push_back(startState);
  148. while (!recursionStateStack.empty()) {
  149. // Peek at the topmost state in the stack, but leave it on there for now.
  150. uint_fast64_t currentState = recursionStateStack.back();
  151. // If the state has not yet been seen, we need to assign it a preorder number and iterate over its successors.
  152. if (!hasPreorderNumber.get(currentState)) {
  153. preorderNumbers[currentState] = currentIndex++;
  154. hasPreorderNumber.set(currentState, true);
  155. s.push_back(currentState);
  156. p.push_back(currentState);
  157. for (auto const& successor : transitionMatrix.getRowGroup(currentState)) {
  158. if (subsystem.get(successor.getColumn()) && successor.getValue() != storm::utility::zero<ValueType>()) {
  159. if (currentState == successor.getColumn()) {
  160. statesWithSelfLoop.set(currentState);
  161. }
  162. if (!hasPreorderNumber.get(successor.getColumn())) {
  163. // In this case, we must recursively visit the successor. We therefore push the state
  164. // onto the recursion stack.
  165. recursionStateStack.push_back(successor.getColumn());
  166. } else {
  167. if (!stateHasScc.get(successor.getColumn())) {
  168. while (preorderNumbers[p.back()] > preorderNumbers[successor.getColumn()]) {
  169. p.pop_back();
  170. }
  171. }
  172. }
  173. }
  174. }
  175. } else {
  176. // In this case, we have searched all successors of the current state and can exit the "recursion"
  177. // on the current state.
  178. if (currentState == p.back()) {
  179. p.pop_back();
  180. uint_fast64_t poppedState = 0;
  181. do {
  182. poppedState = s.back();
  183. s.pop_back();
  184. stateToSccMapping[poppedState] = sccCount;
  185. stateHasScc.set(poppedState);
  186. } while (poppedState != currentState);
  187. ++sccCount;
  188. }
  189. recursionStateStack.pop_back();
  190. }
  191. }
  192. }
  193. // Explicitly instantiate the SCC decomposition.
  194. template class StronglyConnectedComponentDecomposition<double>;
  195. template StronglyConnectedComponentDecomposition<double>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<double> const& model, bool dropNaiveSccs, bool onlyBottomSccs);
  196. template StronglyConnectedComponentDecomposition<double>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<double> const& model, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs);
  197. template StronglyConnectedComponentDecomposition<double>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<double> const& model, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs);
  198. template class StronglyConnectedComponentDecomposition<float>;
  199. template StronglyConnectedComponentDecomposition<float>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<float> const& model, bool dropNaiveSccs, bool onlyBottomSccs);
  200. template StronglyConnectedComponentDecomposition<float>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<float> const& model, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs);
  201. template StronglyConnectedComponentDecomposition<float>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<float> const& model, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs);
  202. #ifdef STORM_HAVE_CARL
  203. template class StronglyConnectedComponentDecomposition<storm::RationalNumber>;
  204. template StronglyConnectedComponentDecomposition<storm::RationalNumber>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<storm::RationalNumber> const& model, bool dropNaiveSccs, bool onlyBottomSccs);
  205. template StronglyConnectedComponentDecomposition<storm::RationalNumber>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<storm::RationalNumber> const& model, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs);
  206. template StronglyConnectedComponentDecomposition<storm::RationalNumber>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<storm::RationalNumber> const& model, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs);
  207. template class StronglyConnectedComponentDecomposition<storm::RationalFunction>;
  208. template StronglyConnectedComponentDecomposition<storm::RationalFunction>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<storm::RationalFunction> const& model, bool dropNaiveSccs, bool onlyBottomSccs);
  209. template StronglyConnectedComponentDecomposition<storm::RationalFunction>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<storm::RationalFunction> const& model, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs);
  210. template StronglyConnectedComponentDecomposition<storm::RationalFunction>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<storm::RationalFunction> const& model, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs);
  211. #endif
  212. } // namespace storage
  213. } // namespace storm