435 lines
29 KiB
435 lines
29 KiB
#include "src/modelchecker/reachability/SparseSccModelChecker.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "src/storage/StronglyConnectedComponentDecomposition.h"
|
|
#include "src/utility/graph.h"
|
|
#include "src/utility/vector.h"
|
|
#include "src/exceptions/InvalidStateException.h"
|
|
#include "src/utility/macros.h"
|
|
|
|
namespace storm {
|
|
namespace modelchecker {
|
|
namespace reachability {
|
|
|
|
template<typename ValueType>
|
|
static ValueType&& simplify(ValueType&& value) {
|
|
// In the general case, we don't to 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 std::forward<ValueType>(value);
|
|
}
|
|
|
|
template<typename IndexType, typename ValueType>
|
|
static storm::storage::MatrixEntry<IndexType, ValueType>&& simplify(storm::storage::MatrixEntry<IndexType, ValueType>&& matrixEntry) {
|
|
simplify(matrixEntry.getValue());
|
|
return std::move(matrixEntry);
|
|
}
|
|
|
|
template<typename IndexType, typename ValueType>
|
|
static storm::storage::MatrixEntry<IndexType, ValueType>& simplify(storm::storage::MatrixEntry<IndexType, ValueType>& matrixEntry) {
|
|
matrixEntry.setValue(simplify(matrixEntry.getValue()));
|
|
return matrixEntry;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
ValueType SparseSccModelChecker<ValueType>::computeReachabilityProbability(storm::models::Dtmc<ValueType> const& dtmc, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) {
|
|
// First, do some sanity checks to establish some required properties.
|
|
STORM_LOG_THROW(dtmc.getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::IllegalArgumentException, "Input model is required to have exactly one initial state.");
|
|
typename FlexibleSparseMatrix<ValueType>::index_type initialStateIndex = *dtmc.getInitialStates().begin();
|
|
|
|
// Then, compute the subset of states that has a probability of 0 or 1, respectively.
|
|
std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 = storm::utility::graph::performProb01(dtmc, phiStates, psiStates);
|
|
storm::storage::BitVector statesWithProbability0 = statesWithProbability01.first;
|
|
storm::storage::BitVector statesWithProbability1 = statesWithProbability01.second;
|
|
storm::storage::BitVector maybeStates = ~(statesWithProbability0 | statesWithProbability1);
|
|
|
|
// If the initial state is known to have either probability 0 or 1, we can directly return the result.
|
|
if (!maybeStates.get(initialStateIndex)) {
|
|
return statesWithProbability0.get(initialStateIndex) ? 0 : 1;
|
|
}
|
|
|
|
// Determine the set of states that is reachable from the initial state without jumping over a target state.
|
|
storm::storage::BitVector reachableStates = storm::utility::graph::getReachableStates(dtmc.getTransitionMatrix(), dtmc.getInitialStates(), maybeStates, statesWithProbability1);
|
|
|
|
// Subtract from the maybe states the set of states that is not reachable (on a path from the initial to a target state).
|
|
maybeStates &= reachableStates;
|
|
|
|
// Create a vector for the probabilities to go to a state with probability 1 in one step.
|
|
std::vector<ValueType> oneStepProbabilities = dtmc.getTransitionMatrix().getConstrainedRowSumVector(maybeStates, statesWithProbability1);
|
|
|
|
// Determine the set of initial states of the sub-DTMC.
|
|
storm::storage::BitVector newInitialStates = dtmc.getInitialStates() % maybeStates;
|
|
|
|
// We then build the submatrix that only has the transitions of the maybe states.
|
|
storm::storage::SparseMatrix<ValueType> submatrix = dtmc.getTransitionMatrix().getSubmatrix(false, maybeStates, maybeStates);
|
|
|
|
// Create a bit vector that represents the subsystem of states we still have to eliminate.
|
|
storm::storage::BitVector subsystem = storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true);
|
|
|
|
// Then, we convert the reduced matrix to a more flexible format to be able to perform state elimination more easily.
|
|
FlexibleSparseMatrix<ValueType> flexibleMatrix = getFlexibleSparseMatrix(submatrix);
|
|
FlexibleSparseMatrix<ValueType> flexibleBackwardTransitions = getFlexibleSparseMatrix(submatrix.transpose(), true);
|
|
|
|
// Then, we recursively treat all SCCs.
|
|
treatScc(dtmc, flexibleMatrix, oneStepProbabilities, newInitialStates, subsystem, submatrix, flexibleBackwardTransitions, false, 0);
|
|
|
|
// Now, we return the value for the only initial state.
|
|
return oneStepProbabilities[initialStateIndex];
|
|
}
|
|
|
|
template<typename ValueType>
|
|
void SparseSccModelChecker<ValueType>::treatScc(storm::models::Dtmc<ValueType> const& dtmc, FlexibleSparseMatrix<ValueType>& matrix, std::vector<ValueType>& oneStepProbabilities, storm::storage::BitVector const& entryStates, storm::storage::BitVector const& scc, storm::storage::SparseMatrix<ValueType> const& forwardTransitions, FlexibleSparseMatrix<ValueType>& backwardTransitions, bool eliminateEntryStates, uint_fast64_t level) {
|
|
// If the SCCs are large enough, we try to split them further.
|
|
if (scc.getNumberOfSetBits() > SparseSccModelChecker<ValueType>::maximalSccSize) {
|
|
// Here, we further decompose the SCC into sub-SCCs.
|
|
storm::storage::StronglyConnectedComponentDecomposition<ValueType> decomposition(forwardTransitions, scc & ~entryStates, false, false);
|
|
|
|
// To eliminate the remaining one-state SCCs, we need to keep track of them.
|
|
// storm::storage::BitVector remainingStates(scc);
|
|
|
|
// Store a bit vector of remaining SCCs so we can be flexible when it comes to the order in which
|
|
// we eliminate the SCCs.
|
|
storm::storage::BitVector remainingSccs(decomposition.size(), true);
|
|
|
|
// First, get rid of the trivial SCCs.
|
|
for (uint_fast64_t sccIndex = 0; sccIndex < decomposition.size(); ++sccIndex) {
|
|
storm::storage::StronglyConnectedComponent const& scc = decomposition.getBlock(sccIndex);
|
|
if (scc.isTrivial()) {
|
|
storm::storage::sparse::state_type onlyState = *scc.begin();
|
|
eliminateState(matrix, oneStepProbabilities, onlyState, backwardTransitions);
|
|
remainingSccs.set(sccIndex, false);
|
|
}
|
|
}
|
|
|
|
// And then recursively treat the remaining sub-SCCs.
|
|
for (auto sccIndex : remainingSccs) {
|
|
storm::storage::StronglyConnectedComponent const& newScc = decomposition.getBlock(sccIndex);
|
|
// If the SCC consists of just one state, we do not explore it recursively, but rather eliminate
|
|
// it directly.
|
|
if (newScc.size() == 1) {
|
|
continue;
|
|
}
|
|
|
|
// Rewrite SCC into bit vector and subtract it from the remaining states.
|
|
storm::storage::BitVector newSccAsBitVector(forwardTransitions.getRowCount(), newScc.begin(), newScc.end());
|
|
// remainingStates &= ~newSccAsBitVector;
|
|
|
|
// Determine the set of entry states of the SCC.
|
|
storm::storage::BitVector entryStates(dtmc.getNumberOfStates());
|
|
for (auto const& state : newScc) {
|
|
for (auto const& predecessor : backwardTransitions.getRow(state)) {
|
|
if (predecessor.getValue() > storm::utility::constantZero<ValueType>() && !newSccAsBitVector.get(predecessor.getColumn())) {
|
|
entryStates.set(state);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Recursively descend in SCC-hierarchy.
|
|
treatScc(dtmc, matrix, oneStepProbabilities, entryStates, newSccAsBitVector, forwardTransitions, backwardTransitions, true, level + 1);
|
|
}
|
|
|
|
// If we are not supposed to eliminate the entry states, we need to take them out of the set of
|
|
// remaining states.
|
|
// if (!eliminateEntryStates) {
|
|
// remainingStates &= ~entryStates;
|
|
// }
|
|
//
|
|
// Now that we eliminated all non-trivial sub-SCCs, we need to take care of trivial sub-SCCs.
|
|
// Therefore, we need to eliminate all states.
|
|
// for (auto const& state : remainingStates) {
|
|
// eliminateState(matrix, oneStepProbabilities, state, backwardTransitions);
|
|
// }
|
|
} else {
|
|
// In this case, we perform simple state elimination in the current SCC.
|
|
storm::storage::BitVector remainingStates = scc;
|
|
|
|
// if (eliminateEntryStates) {
|
|
remainingStates &= ~entryStates;
|
|
// }
|
|
|
|
// Eliminate the remaining states.
|
|
for (auto const& state : remainingStates) {
|
|
eliminateState(matrix, oneStepProbabilities, state, backwardTransitions);
|
|
}
|
|
|
|
// Finally, eliminate the entry states (if we are allowed to do so).
|
|
if (eliminateEntryStates) {
|
|
for (auto state : entryStates) {
|
|
eliminateState(matrix, oneStepProbabilities, state, backwardTransitions);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename ValueType>
|
|
void SparseSccModelChecker<ValueType>::eliminateState(FlexibleSparseMatrix<ValueType>& matrix, std::vector<ValueType>& oneStepProbabilities, uint_fast64_t state, FlexibleSparseMatrix<ValueType>& backwardTransitions) {
|
|
bool hasSelfLoop = false;
|
|
ValueType loopProbability = storm::utility::constantZero<ValueType>();
|
|
|
|
// Start by finding loop probability.
|
|
typename FlexibleSparseMatrix<ValueType>::row_type& currentStateSuccessors = matrix.getRow(state);
|
|
for (auto const& entry : currentStateSuccessors) {
|
|
if (entry.getColumn() >= state) {
|
|
if (entry.getColumn() == state) {
|
|
loopProbability = entry.getValue();
|
|
hasSelfLoop = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Scale all entries in this row with (1 / (1 - loopProbability)) only in case there was a self-loop.
|
|
if (hasSelfLoop) {
|
|
loopProbability = 1 / (1 - loopProbability);
|
|
simplify(loopProbability);
|
|
for (auto& entry : matrix.getRow(state)) {
|
|
entry.setValue(simplify(entry.getValue() * loopProbability));
|
|
}
|
|
oneStepProbabilities[state] = simplify(oneStepProbabilities[state] * loopProbability);
|
|
}
|
|
|
|
// Now connect the predecessors of the state being eliminated with its successors.
|
|
typename FlexibleSparseMatrix<ValueType>::row_type& currentStatePredecessors = backwardTransitions.getRow(state);
|
|
for (auto const& predecessorEntry : currentStatePredecessors) {
|
|
uint_fast64_t predecessor = predecessorEntry.getColumn();
|
|
|
|
// Skip the state itself as one of its predecessors.
|
|
if (predecessor == state) {
|
|
continue;
|
|
}
|
|
|
|
// First, find the probability with which the predecessor can move to the current state, because
|
|
// the other probabilities need to be scaled with this factor.
|
|
typename FlexibleSparseMatrix<ValueType>::row_type& predecessorForwardTransitions = matrix.getRow(predecessor);
|
|
typename FlexibleSparseMatrix<ValueType>::row_type::iterator multiplyElement = std::find_if(predecessorForwardTransitions.begin(), predecessorForwardTransitions.end(), [&](storm::storage::MatrixEntry<typename FlexibleSparseMatrix<ValueType>::index_type, typename FlexibleSparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() == state; });
|
|
|
|
// Make sure we have found the probability and set it to zero.
|
|
STORM_LOG_THROW(multiplyElement != predecessorForwardTransitions.end(), storm::exceptions::InvalidStateException, "No probability for successor found.");
|
|
ValueType multiplyFactor = multiplyElement->getValue();
|
|
multiplyElement->setValue(0);
|
|
|
|
// At this point, we need to update the (forward) transitions of the predecessor.
|
|
typename FlexibleSparseMatrix<ValueType>::row_type::iterator first1 = predecessorForwardTransitions.begin();
|
|
typename FlexibleSparseMatrix<ValueType>::row_type::iterator last1 = predecessorForwardTransitions.end();
|
|
typename FlexibleSparseMatrix<ValueType>::row_type::iterator first2 = currentStateSuccessors.begin();
|
|
typename FlexibleSparseMatrix<ValueType>::row_type::iterator last2 = currentStateSuccessors.end();
|
|
|
|
typename FlexibleSparseMatrix<ValueType>::row_type newSuccessors;
|
|
newSuccessors.reserve((last1 - first1) + (last2 - first2));
|
|
std::insert_iterator<typename FlexibleSparseMatrix<ValueType>::row_type> result(newSuccessors, newSuccessors.end());
|
|
|
|
// Now we merge the two successor lists. (Code taken from std::set_union and modified to suit our needs).
|
|
for (; first1 != last1; ++result) {
|
|
// Skip the transitions to the state that is currently being eliminated.
|
|
if (first1->getColumn() == state || (first2 != last2 && first2->getColumn() == state)) {
|
|
if (first1->getColumn() == state) {
|
|
++first1;
|
|
}
|
|
if (first2 != last2 && first2->getColumn() == state) {
|
|
++first2;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (first2 == last2) {
|
|
std::copy_if(first1, last1, result, [&] (storm::storage::MatrixEntry<typename FlexibleSparseMatrix<ValueType>::index_type, typename FlexibleSparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() != state; } );
|
|
break;
|
|
}
|
|
if (first2->getColumn() < first1->getColumn()) {
|
|
*result = simplify(*first2 * multiplyFactor);
|
|
++first2;
|
|
} else if (first1->getColumn() < first2->getColumn()) {
|
|
*result = *first1;
|
|
++first1;
|
|
} else {
|
|
*result = storm::storage::MatrixEntry<typename FlexibleSparseMatrix<ValueType>::index_type, typename FlexibleSparseMatrix<ValueType>::value_type>(first1->getColumn(), simplify(first1->getValue() + simplify(multiplyFactor * first2->getValue())));
|
|
++first1;
|
|
++first2;
|
|
}
|
|
}
|
|
for (; first2 != last2; ++first2) {
|
|
if (first2->getColumn() != state) {
|
|
*result = simplify(*first2 * multiplyFactor);
|
|
}
|
|
}
|
|
|
|
// Now move the new transitions in place.
|
|
predecessorForwardTransitions = std::move(newSuccessors);
|
|
|
|
// Add the probabilities to go to a target state in just one step.
|
|
oneStepProbabilities[predecessor] = simplify(oneStepProbabilities[predecessor] + simplify(multiplyFactor * oneStepProbabilities[state]));
|
|
}
|
|
|
|
// Finally, we need to add the predecessor to the set of predecessors of every successor.
|
|
for (auto const& successorEntry : currentStateSuccessors) {
|
|
typename FlexibleSparseMatrix<ValueType>::row_type& successorBackwardTransitions = backwardTransitions.getRow(successorEntry.getColumn());
|
|
|
|
// Delete the current state as a predecessor of the successor state.
|
|
typename FlexibleSparseMatrix<ValueType>::row_type::iterator elimIt = std::find_if(successorBackwardTransitions.begin(), successorBackwardTransitions.end(), [&](storm::storage::MatrixEntry<typename FlexibleSparseMatrix<ValueType>::index_type, typename FlexibleSparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() == state; });
|
|
if (elimIt != successorBackwardTransitions.end()) {
|
|
successorBackwardTransitions.erase(elimIt);
|
|
}
|
|
|
|
typename FlexibleSparseMatrix<ValueType>::row_type::iterator first1 = successorBackwardTransitions.begin();
|
|
typename FlexibleSparseMatrix<ValueType>::row_type::iterator last1 = successorBackwardTransitions.end();
|
|
typename FlexibleSparseMatrix<ValueType>::row_type::iterator first2 = currentStatePredecessors.begin();
|
|
typename FlexibleSparseMatrix<ValueType>::row_type::iterator last2 = currentStatePredecessors.end();
|
|
|
|
typename FlexibleSparseMatrix<ValueType>::row_type newPredecessors;
|
|
newPredecessors.reserve((last1 - first1) + (last2 - first2));
|
|
std::insert_iterator<typename FlexibleSparseMatrix<ValueType>::row_type> result(newPredecessors, newPredecessors.end());
|
|
|
|
|
|
for (; first1 != last1; ++result) {
|
|
if (first2 == last2) {
|
|
std::copy_if(first1, last1, result, [&] (storm::storage::MatrixEntry<typename FlexibleSparseMatrix<ValueType>::index_type, typename FlexibleSparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() != state; });
|
|
break;
|
|
}
|
|
if (first2->getColumn() < first1->getColumn()) {
|
|
if (first2->getColumn() != state) {
|
|
*result = *first2;
|
|
}
|
|
++first2;
|
|
} else {
|
|
if (first1->getColumn() != state) {
|
|
*result = *first1;
|
|
}
|
|
if (first1->getColumn() == first2->getColumn()) {
|
|
++first2;
|
|
}
|
|
++first1;
|
|
}
|
|
}
|
|
std::copy_if(first2, last2, result, [&] (storm::storage::MatrixEntry<typename FlexibleSparseMatrix<ValueType>::index_type, typename FlexibleSparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() != state; });
|
|
|
|
// Now move the new predecessors in place.
|
|
successorBackwardTransitions = std::move(newPredecessors);
|
|
}
|
|
|
|
|
|
// Clear the eliminated row to reduce memory consumption.
|
|
currentStateSuccessors.clear();
|
|
currentStateSuccessors.shrink_to_fit();
|
|
}
|
|
|
|
template <typename ValueType>
|
|
bool SparseSccModelChecker<ValueType>::eliminateStateInPlace(storm::storage::SparseMatrix<ValueType>& matrix, std::vector<ValueType>& oneStepProbabilities, uint_fast64_t state, storm::storage::SparseMatrix<ValueType>& backwardTransitions) {
|
|
typename storm::storage::SparseMatrix<ValueType>::iterator forwardElement = matrix.getRow(state).begin();
|
|
typename storm::storage::SparseMatrix<ValueType>::iterator backwardElement = backwardTransitions.getRow(state).begin();
|
|
|
|
if (forwardElement->getValue() != storm::utility::constantOne<ValueType>() || backwardElement->getValue() != storm::utility::constantOne<ValueType>()) {
|
|
return false;
|
|
}
|
|
|
|
std::cout << "eliminating " << state << std::endl;
|
|
std::cout << "fwd element: " << *forwardElement << " and bwd element: " << *backwardElement << std::endl;
|
|
|
|
// Find the element of the predecessor that moves to the state that we want to eliminate.
|
|
typename storm::storage::SparseMatrix<ValueType>::rows forwardRow = matrix.getRow(backwardElement->getColumn());
|
|
typename storm::storage::SparseMatrix<ValueType>::iterator multiplyElement = std::find_if(forwardRow.begin(), forwardRow.end(), [&](storm::storage::MatrixEntry<typename storm::storage::SparseMatrix<ValueType>::index_type, typename storm::storage::SparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() == state; });
|
|
|
|
std::cout << "before fwd: " << std::endl;
|
|
for (auto element : matrix.getRow(backwardElement->getColumn())) {
|
|
std::cout << element << ", " << std::endl;
|
|
}
|
|
|
|
// Modify the forward probability entry of the predecessor.
|
|
multiplyElement->setValue(multiplyElement->getValue() * forwardElement->getValue());
|
|
multiplyElement->setColumn(forwardElement->getColumn());
|
|
|
|
// Modify the one-step probability for the predecessor if necessary.
|
|
if (oneStepProbabilities[state] != storm::utility::constantZero<ValueType>()) {
|
|
oneStepProbabilities[backwardElement->getColumn()] += multiplyElement->getValue() * oneStepProbabilities[state];
|
|
}
|
|
|
|
// If the forward entry is not at the right position, we need to move it there.
|
|
if (multiplyElement != forwardRow.begin() && multiplyElement->getColumn() < (multiplyElement - 1)->getColumn()) {
|
|
while (multiplyElement != forwardRow.begin() && multiplyElement->getColumn() < (multiplyElement - 1)->getColumn()) {
|
|
std::swap(*multiplyElement, *(multiplyElement - 1));
|
|
--multiplyElement;
|
|
}
|
|
} else if ((multiplyElement + 1) != forwardRow.end() && multiplyElement->getColumn() > (multiplyElement + 1)->getColumn()) {
|
|
while ((multiplyElement + 1) != forwardRow.end() && multiplyElement->getColumn() > (multiplyElement + 1)->getColumn()) {
|
|
std::swap(*multiplyElement, *(multiplyElement + 1));
|
|
++multiplyElement;
|
|
}
|
|
}
|
|
|
|
std::cout << "after fwd: " << std::endl;
|
|
for (auto element : matrix.getRow(backwardElement->getColumn())) {
|
|
std::cout << element << ", " << std::endl;
|
|
}
|
|
|
|
// Find the backward element of the successor that moves to the state that we want to eliminate.
|
|
typename storm::storage::SparseMatrix<ValueType>::rows backwardRow = backwardTransitions.getRow(forwardElement->getColumn());
|
|
typename storm::storage::SparseMatrix<ValueType>::iterator backwardEntry = std::find_if(backwardRow.begin(), backwardRow.end(), [&](storm::storage::MatrixEntry<typename storm::storage::SparseMatrix<ValueType>::index_type, typename storm::storage::SparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() == state; });
|
|
|
|
std::cout << "before bwd" << std::endl;
|
|
for (auto element : backwardTransitions.getRow(forwardElement->getColumn())) {
|
|
std::cout << element << ", " << std::endl;
|
|
}
|
|
|
|
// Modify the predecessor list of the successor and add the predecessor of the state we eliminate.
|
|
backwardEntry->setColumn(backwardElement->getColumn());
|
|
|
|
// If the backward entry is not at the right position, we need to move it there.
|
|
if (backwardEntry != backwardRow.begin() && backwardEntry->getColumn() < (backwardEntry - 1)->getColumn()) {
|
|
while (backwardEntry != backwardRow.begin() && backwardEntry->getColumn() < (backwardEntry - 1)->getColumn()) {
|
|
std::swap(*backwardEntry, *(backwardEntry - 1));
|
|
--backwardEntry;
|
|
}
|
|
} else if ((backwardEntry + 1) != backwardRow.end() && backwardEntry->getColumn() > (backwardEntry + 1)->getColumn()) {
|
|
while ((backwardEntry + 1) != backwardRow.end() && backwardEntry->getColumn() > (backwardEntry + 1)->getColumn()) {
|
|
std::swap(*backwardEntry, *(backwardEntry + 1));
|
|
++backwardEntry;
|
|
}
|
|
}
|
|
|
|
std::cout << "after bwd" << std::endl;
|
|
for (auto element : backwardTransitions.getRow(forwardElement->getColumn())) {
|
|
std::cout << element << ", " << std::endl;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
FlexibleSparseMatrix<ValueType>::FlexibleSparseMatrix(index_type rows) : data(rows) {
|
|
// Intentionally left empty.
|
|
}
|
|
|
|
template<typename ValueType>
|
|
void FlexibleSparseMatrix<ValueType>::reserveInRow(index_type row, index_type numberOfElements) {
|
|
this->data[row].reserve(numberOfElements);
|
|
}
|
|
|
|
template<typename ValueType>
|
|
typename FlexibleSparseMatrix<ValueType>::row_type& FlexibleSparseMatrix<ValueType>::getRow(index_type index) {
|
|
return this->data[index];
|
|
}
|
|
|
|
template<typename ValueType>
|
|
FlexibleSparseMatrix<ValueType> SparseSccModelChecker<ValueType>::getFlexibleSparseMatrix(storm::storage::SparseMatrix<ValueType> const& matrix, bool setAllValuesToOne) {
|
|
FlexibleSparseMatrix<ValueType> flexibleMatrix(matrix.getRowCount());
|
|
|
|
for (typename FlexibleSparseMatrix<ValueType>::index_type rowIndex = 0; rowIndex < matrix.getRowCount(); ++rowIndex) {
|
|
typename storm::storage::SparseMatrix<ValueType>::const_rows row = matrix.getRow(rowIndex);
|
|
flexibleMatrix.reserveInRow(rowIndex, row.getNumberOfEntries());
|
|
|
|
for (auto const& element : row) {
|
|
if (setAllValuesToOne) {
|
|
flexibleMatrix.getRow(rowIndex).emplace_back(element.getColumn(), storm::utility::constantOne<ValueType>());
|
|
} else {
|
|
flexibleMatrix.getRow(rowIndex).emplace_back(element);
|
|
}
|
|
}
|
|
}
|
|
|
|
return flexibleMatrix;
|
|
}
|
|
|
|
template class FlexibleSparseMatrix<double>;
|
|
template class SparseSccModelChecker<double>;
|
|
|
|
} // namespace reachability
|
|
} // namespace modelchecker
|
|
} // namespace storm
|