Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
AcyclicSolverHelper.h
Go to the documentation of this file.
8
9namespace storm {
10namespace solver {
11
12namespace helper {
13
19template<typename ValueType>
20boost::optional<std::vector<uint64_t>> computeTopologicalGroupOrdering(storm::storage::SparseMatrix<ValueType> const& matrix) {
21 uint64_t numGroups = matrix.getRowGroupCount();
22 bool orderedMatrixRequired = false;
23 std::vector<uint64_t> result;
24 result.reserve(numGroups);
25 storm::storage::BitVector processed(numGroups, false);
26 storm::storage::BitVector visited(numGroups, false);
27 std::vector<uint64_t> stack;
28
29 // It's more likely that states without a successor are located at the end (due to the way we build the model).
30 // We therefore process the matrix in reverse order.
31 uint64_t startState = numGroups;
32 while (startState > 0) {
33 --startState;
34 // skip already processed states
35 if (processed.get(startState))
36 continue;
37
38 // Now do a dfs from start state.
39 stack.push_back(startState);
40 while (!stack.empty()) {
41 uint64_t current = stack.back();
42 if (visited.get(current)) {
43 // We are backtracking, so add this state now
44 // It might be that we already processed this state before. This can happen, e.g., if this state has two direct predecessors, A and B, and
45 // A is also a predecessor of B. Then, this node gets inserted into the stack two times: when analyzing A and B.
46 if (!processed.get(current)) {
47 result.push_back(current);
48 processed.set(current);
49 }
50 stack.pop_back();
51 } else {
52 visited.set(current);
53 for (auto const& entry : matrix.getRowGroup(current)) {
54 if (!processed.get(entry.getColumn()) && !storm::utility::isZero(entry.getValue())) {
55 orderedMatrixRequired = true;
56 STORM_LOG_THROW(!visited.get(entry.getColumn()), storm::exceptions::UnmetRequirementException, "The model is not acyclic.");
57 stack.push_back(entry.getColumn());
58 }
59 }
60 // If there are no successors to process, we will add the current state to the result in the next iteration.
61 }
62 }
63 }
64 // we will do backwards iterations, so the order has to be reversed
65 if (orderedMatrixRequired) {
66 std::reverse(result.begin(), result.end());
67 STORM_LOG_ASSERT(result.size() == matrix.getRowGroupCount(), "Result vector has an unexpected amount of entries.");
68 return result;
69 } else {
70 return boost::none;
71 }
72}
73
76template<typename ValueType>
78 std::vector<uint64_t> const& newToOrigIndexMap,
79 std::vector<std::pair<uint64_t, ValueType>>& bFactors) {
80 std::vector<uint64_t> origToNewMap(newToOrigIndexMap.size(), std::numeric_limits<uint64_t>::max());
81 for (uint64_t i = 0; i < newToOrigIndexMap.size(); ++i) {
82 origToNewMap[newToOrigIndexMap[i]] = i;
83 }
84
85 bool hasRowGrouping = !matrix.hasTrivialRowGrouping();
86 storm::storage::SparseMatrixBuilder<ValueType> builder(matrix.getRowCount(), matrix.getColumnCount(), matrix.getNonzeroEntryCount(), false, hasRowGrouping,
87 hasRowGrouping ? matrix.getRowGroupCount() : static_cast<uint64_t>(0));
88 uint64_t newRow = 0;
89 for (uint64_t newRowGroup = 0; newRowGroup < newToOrigIndexMap.size(); ++newRowGroup) {
90 auto const& origRowGroup = newToOrigIndexMap[newRowGroup];
91 if (hasRowGrouping) {
92 builder.newRowGroup(newRow);
93 }
94 for (uint64_t origRow = matrix.getRowGroupIndices()[origRowGroup]; origRow < matrix.getRowGroupIndices()[origRowGroup + 1]; ++origRow) {
95 for (auto const& entry : matrix.getRow(origRow)) {
96 if (storm::utility::isZero(entry.getValue())) {
97 continue;
98 }
99 if (entry.getColumn() == origRowGroup) {
100 if (storm::utility::isOne(entry.getValue())) {
101 // a one selfloop can only mean that there is never a non-zero value at the b vector for the current row.
102 // Let's "assert" this by considering infinity. (This is necessary to avoid division by zero)
103 bFactors.emplace_back(newRow, storm::utility::infinity<ValueType>());
104 }
105 ValueType factor = storm::utility::one<ValueType>() / (storm::utility::one<ValueType>() - entry.getValue());
106 bFactors.emplace_back(newRow, factor);
107 }
108 builder.addNextValue(newRow, origToNewMap[entry.getColumn()], entry.getValue());
109 }
110 ++newRow;
111 }
112 }
113 auto result = builder.build(matrix.getRowCount(), matrix.getColumnCount(), matrix.getRowGroupCount());
114 // apply the bFactors to the relevant rows
115 for (auto const& bFactor : bFactors) {
116 STORM_LOG_ASSERT(!storm::utility::isInfinity(bFactor.second) || storm::utility::isZero(result.getRowSum(bFactor.first)),
117 "The input matrix does not seem to be probabilistic.");
118 for (auto& entry : result.getRow(bFactor.first)) {
119 entry.setValue(entry.getValue() * bFactor.second);
120 }
121 }
122 STORM_LOG_DEBUG("Reordered " << matrix.getDimensionsAsString() << " with " << bFactors.size() << " selfloop entries for acyclic solving.");
123 return result;
124}
125} // namespace helper
126} // namespace solver
127} // namespace storm
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
void set(uint_fast64_t index, bool value=true)
Sets the given truth value at the given index.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
A class that can be used to build a sparse matrix by adding value by value.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
void newRowGroup(index_type startingRow)
Starts a new row group in the matrix.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
A class that holds a possibly non-square matrix in the compressed row storage format.
const_rows getRow(index_type row) const
Returns an object representing the given row.
const_rows getRowGroup(index_type rowGroup) const
Returns an object representing the given row group.
index_type getRowGroupCount() const
Returns the number of row groups in the matrix.
std::string getDimensionsAsString() const
Returns a string describing the dimensions of the matrix.
index_type getColumnCount() const
Returns the number of columns of the matrix.
bool hasTrivialRowGrouping() const
Retrieves whether the matrix has a trivial row grouping.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
index_type getRowCount() const
Returns the number of rows of the matrix.
index_type getNonzeroEntryCount() const
Returns the cached number of nonzero entries in the matrix.
#define STORM_LOG_DEBUG(message)
Definition logging.h:23
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
storm::storage::SparseMatrix< ValueType > createReorderedMatrix(storm::storage::SparseMatrix< ValueType > const &matrix, std::vector< uint64_t > const &newToOrigIndexMap, std::vector< std::pair< uint64_t, ValueType > > &bFactors)
reorders the row group such that the i'th row of the new matrix corresponds to the order[i]'th row of...
boost::optional< std::vector< uint64_t > > computeTopologicalGroupOrdering(storm::storage::SparseMatrix< ValueType > const &matrix)
Returns a reordering of the matrix row(groups) and columns such that we can solve the (minmax or line...
bool isOne(ValueType const &a)
Definition constants.cpp:36
bool isZero(ValueType const &a)
Definition constants.cpp:41
bool isInfinity(ValueType const &a)
Definition constants.cpp:71
LabParser.cpp.
Definition cli.cpp:18