Browse Source

Merge branch 'exact_equation_solver' into monolithic-dft

Former-commit-id: 6d256e687f
main
Mavo 9 years ago
parent
commit
2a65257571
  1. 9
      src/adapters/CarlAdapter.h
  2. 459
      src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp
  3. 95
      src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h
  4. 62
      src/solver/EliminationLinearEquationSolver.cpp
  5. 34
      src/solver/EliminationLinearEquationSolver.h
  6. 2
      src/solver/NativeLinearEquationSolver.h
  7. 53
      src/solver/stateelimination/ConditionalEliminator.cpp
  8. 53
      src/solver/stateelimination/ConditionalEliminator.h
  9. 47
      src/solver/stateelimination/LongRunAverageEliminator.cpp
  10. 36
      src/solver/stateelimination/LongRunAverageEliminator.h
  11. 45
      src/solver/stateelimination/PrioritizedEliminator.cpp
  12. 34
      src/solver/stateelimination/PrioritizedEliminator.h
  13. 259
      src/solver/stateelimination/StateEliminator.cpp
  14. 42
      src/solver/stateelimination/StateEliminator.h
  15. 161
      src/storage/FlexibleSparseMatrix.cpp
  16. 163
      src/storage/FlexibleSparseMatrix.h
  17. 5
      src/storage/SparseMatrix.cpp
  18. 7
      src/storage/SparseMatrix.h
  19. 4
      src/storage/expressions/ToRationalFunctionVisitor.cpp
  20. 2
      src/utility/vector.h

9
src/adapters/CarlAdapter.h

@ -4,6 +4,8 @@
// Include config to know whether CARL is available or not.
#include "storm-config.h"
#include <boost/multiprecision/gmp.hpp>
#ifdef STORM_HAVE_CARL
#include <carl/numbers/numbers.h>
@ -42,9 +44,12 @@ namespace carl {
}
namespace storm {
typedef cln::cl_RA RationalNumber;
// typedef boost::multiprecision::gmp_rational RationalNumber;
typedef boost::multiprecision::number<boost::multiprecision::gmp_rational> RationalNumber;
typedef cln::cl_RA CarlRationalNumber;
typedef carl::Variable Variable;
typedef carl::MultivariatePolynomial<RationalNumber> RawPolynomial;
typedef carl::MultivariatePolynomial<CarlRationalNumber> RawPolynomial;
typedef carl::FactorizedPolynomial<RawPolynomial> Polynomial;
typedef carl::Relation CompareRelation;

459
src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp

@ -25,6 +25,10 @@
#include "src/exceptions/InvalidSettingsException.h"
#include "src/exceptions/IllegalArgumentException.h"
#include "src/solver/stateelimination/LongRunAverageEliminator.h"
#include "src/solver/stateelimination/ConditionalEliminator.h"
#include "src/solver/stateelimination/PrioritizedEliminator.h"
namespace storm {
namespace modelchecker {
@ -260,10 +264,10 @@ namespace storm {
std::chrono::high_resolution_clock::time_point conversionStart = std::chrono::high_resolution_clock::now();
// Then, we convert the reduced matrix to a more flexible format to be able to perform state elimination more easily.
FlexibleSparseMatrix flexibleMatrix = getFlexibleSparseMatrix(transitionMatrix);
flexibleMatrix.filter(maybeStates, maybeStates);
FlexibleSparseMatrix flexibleBackwardTransitions = getFlexibleSparseMatrix(backwardTransitions);
flexibleBackwardTransitions.filter(maybeStates, maybeStates);
storm::storage::FlexibleSparseMatrix<ValueType> flexibleMatrix(transitionMatrix);
flexibleMatrix.createSubmatrix(maybeStates, maybeStates);
storm::storage::FlexibleSparseMatrix<ValueType> flexibleBackwardTransitions(backwardTransitions);
flexibleBackwardTransitions.createSubmatrix(maybeStates, maybeStates);
auto conversionEnd = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point modelCheckingStart = std::chrono::high_resolution_clock::now();
@ -300,31 +304,14 @@ namespace storm {
std::vector<ValueType> averageTimeInStates(stateValues.size(), storm::utility::one<ValueType>());
// First, we eliminate all states in BSCCs (except for the representative states).
{
std::unique_ptr<StatePriorityQueue> priorityQueue = createStatePriorityQueue(distanceBasedPriorities, flexibleMatrix, flexibleBackwardTransitions, stateValues, regularStatesInBsccs);
ValueUpdateCallback valueUpdateCallback = [&stateValues,&averageTimeInStates] (storm::storage::sparse::state_type const& state, ValueType const& loopProbability) {
stateValues[state] = storm::utility::simplify(loopProbability * stateValues[state]);
averageTimeInStates[state] = storm::utility::simplify(loopProbability * averageTimeInStates[state]);
};
PredecessorUpdateCallback predecessorCallback = [&stateValues,&averageTimeInStates] (storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) {
stateValues[predecessor] = storm::utility::simplify(stateValues[predecessor] + storm::utility::simplify(probability * stateValues[state]));
averageTimeInStates[predecessor] = storm::utility::simplify(averageTimeInStates[predecessor] + storm::utility::simplify(probability * averageTimeInStates[state]));
};
boost::optional<PriorityUpdateCallback> priorityUpdateCallback = PriorityUpdateCallback([&flexibleMatrix,&flexibleBackwardTransitions,&stateValues,&priorityQueue] (storm::storage::sparse::state_type const& state) {
priorityQueue->update(state, flexibleMatrix, flexibleBackwardTransitions, stateValues);
});
boost::optional<PredecessorFilterCallback> predecessorFilterCallback = boost::none;
std::unique_ptr<StatePriorityQueue<ValueType>> priorityQueue = createStatePriorityQueue(distanceBasedPriorities, flexibleMatrix, flexibleBackwardTransitions, stateValues, regularStatesInBsccs);
storm::solver::stateelimination::LongRunAverageEliminator<SparseDtmcModelType> stateEliminator(flexibleMatrix, flexibleBackwardTransitions, *priorityQueue, stateValues, averageTimeInStates);
while (priorityQueue->hasNextState()) {
storm::storage::sparse::state_type state = priorityQueue->popNextState();
eliminateState(state, flexibleMatrix, flexibleBackwardTransitions, valueUpdateCallback, predecessorCallback, priorityUpdateCallback, predecessorFilterCallback, true);
stateEliminator.eliminateState(state, true);
STORM_LOG_ASSERT(checkConsistent(flexibleMatrix, flexibleBackwardTransitions), "The forward and backward transition matrices became inconsistent.");
}
}
// Now, we set the values of all states in BSCCs to that of the representative value (and clear the
// transitions of the representative states while doing so).
@ -345,11 +332,11 @@ namespace storm {
stateValues[*representativeIt] = bsccValue;
}
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::row_type& representativeForwardRow = flexibleMatrix.getRow(*representativeIt);
FlexibleRowType& representativeForwardRow = flexibleMatrix.getRow(*representativeIt);
representativeForwardRow.clear();
representativeForwardRow.shrink_to_fit();
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::row_type& representativeBackwardRow = flexibleBackwardTransitions.getRow(*representativeIt);
FlexibleRowType& representativeBackwardRow = flexibleBackwardTransitions.getRow(*representativeIt);
auto it = representativeBackwardRow.begin(), ite = representativeBackwardRow.end();
for (; it != ite; ++it) {
if (it->getColumn() == *representativeIt) {
@ -752,21 +739,24 @@ namespace storm {
eliminationOrderNeedsReversedDistances(order));
}
FlexibleSparseMatrix flexibleMatrix = getFlexibleSparseMatrix(submatrix);
FlexibleSparseMatrix flexibleBackwardTransitions = getFlexibleSparseMatrix(submatrixTransposed, true);
std::chrono::high_resolution_clock::time_point conversionStart = std::chrono::high_resolution_clock::now();
storm::storage::FlexibleSparseMatrix<ValueType> flexibleMatrix(submatrix);
storm::storage::FlexibleSparseMatrix<ValueType> flexibleBackwardTransitions(submatrixTransposed, true);
std::chrono::high_resolution_clock::time_point conversionEnd = std::chrono::high_resolution_clock::now();
std::unique_ptr<StatePriorityQueue<ValueType>> statePriorities = createStatePriorityQueue(distanceBasedPriorities, flexibleMatrix, flexibleBackwardTransitions, oneStepProbabilities, statesToEliminate);
std::unique_ptr<StatePriorityQueue> statePriorities = createStatePriorityQueue(distanceBasedPriorities, flexibleMatrix, flexibleBackwardTransitions, oneStepProbabilities, statesToEliminate);
STORM_LOG_INFO("Computing conditional probilities." << std::endl);
std::chrono::high_resolution_clock::time_point modelCheckingStart = std::chrono::high_resolution_clock::now();
uint_fast64_t numberOfStatesToEliminate = statePriorities->size();
STORM_LOG_INFO("Eliminating " << numberOfStatesToEliminate << " states using the state elimination technique." << std::endl);
performPrioritizedStateElimination(statePriorities, flexibleMatrix, flexibleBackwardTransitions, oneStepProbabilities, this->getModel().getInitialStates(), true);
// Prepare some callbacks for the elimination procedure.
ValueUpdateCallback valueUpdateCallback = [&oneStepProbabilities] (storm::storage::sparse::state_type const& state, ValueType const& loopProbability) { oneStepProbabilities[state] = storm::utility::simplify(loopProbability * oneStepProbabilities[state]); };
PredecessorUpdateCallback predecessorUpdateCallback = [&oneStepProbabilities] (storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) { oneStepProbabilities[predecessor] = storm::utility::simplify(oneStepProbabilities[predecessor] * storm::utility::simplify(probability * oneStepProbabilities[state])); };
boost::optional<PredecessorFilterCallback> phiFilterCallback = PredecessorFilterCallback([&phiStates] (storm::storage::sparse::state_type const& state) { return phiStates.get(state); });
boost::optional<PredecessorFilterCallback> psiFilterCallback = PredecessorFilterCallback([&psiStates] (storm::storage::sparse::state_type const& state) { return psiStates.get(state); });
storm::solver::stateelimination::ConditionalEliminator<SparseDtmcModelType> stateEliminator = storm::solver::stateelimination::ConditionalEliminator<SparseDtmcModelType>(flexibleMatrix, flexibleBackwardTransitions, oneStepProbabilities, phiStates, psiStates);
// Eliminate the transitions going into the initial state (if there are any).
if (!flexibleBackwardTransitions.getRow(*newInitialStates.begin()).empty()) {
eliminateState(*newInitialStates.begin(), flexibleMatrix, flexibleBackwardTransitions, valueUpdateCallback, predecessorUpdateCallback, boost::none, boost::none, false);
stateEliminator.eliminateState(*newInitialStates.begin(), false);
}
// Now we need to basically eliminate all chains of not-psi states after phi states and chains of not-phi
@ -797,11 +787,13 @@ namespace storm {
for (auto const& element : currentRow) {
// If any of the successors is a phi state, we eliminate it (wrt. all its phi predecessors).
if (!psiStates.get(element.getColumn())) {
typename FlexibleSparseMatrix::row_type const& successorRow = flexibleMatrix.getRow(element.getColumn());
FlexibleRowType const& successorRow = flexibleMatrix.getRow(element.getColumn());
// Eliminate the successor only if there possibly is a psi state reachable through it.
if (successorRow.size() > 1 || (!successorRow.empty() && successorRow.front().getColumn() != element.getColumn())) {
STORM_LOG_TRACE("Found non-psi successor " << element.getColumn() << " that needs to be eliminated.");
eliminateState(element.getColumn(), flexibleMatrix, flexibleBackwardTransitions, valueUpdateCallback, predecessorUpdateCallback, boost::none, phiFilterCallback, false);
stateEliminator.setStatePhi();
stateEliminator.eliminateState(element.getColumn(), false);
stateEliminator.clearState();
hasNonPsiSuccessor = true;
}
}
@ -827,10 +819,12 @@ namespace storm {
for (auto const& element : currentRow) {
// If any of the successors is a psi state, we eliminate it (wrt. all its psi predecessors).
if (!phiStates.get(element.getColumn())) {
typename FlexibleSparseMatrix::row_type const& successorRow = flexibleMatrix.getRow(element.getColumn());
FlexibleRowType const& successorRow = flexibleMatrix.getRow(element.getColumn());
if (successorRow.size() > 1 || (!successorRow.empty() && successorRow.front().getColumn() != element.getColumn())) {
STORM_LOG_TRACE("Found non-phi successor " << element.getColumn() << " that needs to be eliminated.");
eliminateState(element.getColumn(), flexibleMatrix, flexibleBackwardTransitions, valueUpdateCallback, predecessorUpdateCallback, boost::none, psiFilterCallback, false);
stateEliminator.setStatePsi();
stateEliminator.eliminateState(element.getColumn(), false);
stateEliminator.clearState();
hasNonPhiSuccessor = true;
}
}
@ -877,7 +871,7 @@ namespace storm {
}
template<typename SparseDtmcModelType>
std::unique_ptr<typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::StatePriorityQueue> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::createStatePriorityQueue(boost::optional<std::vector<uint_fast64_t>> const& distanceBasedStatePriorities, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<typename SparseDtmcModelType::ValueType>& oneStepProbabilities, storm::storage::BitVector const& states) {
std::unique_ptr<StatePriorityQueue<typename SparseDtmcModelType::ValueType>> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::createStatePriorityQueue(boost::optional<std::vector<uint_fast64_t>> const& distanceBasedStatePriorities, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType>& oneStepProbabilities, storm::storage::BitVector const& states) {
STORM_LOG_TRACE("Creating state priority queue for states " << states);
@ -921,23 +915,20 @@ namespace storm {
}
template<typename SparseDtmcModelType>
std::unique_ptr<typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::StatePriorityQueue> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::createNaivePriorityQueue(storm::storage::BitVector const& states) {
std::unique_ptr<StatePriorityQueue<typename SparseDtmcModelType::ValueType>> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::createNaivePriorityQueue(storm::storage::BitVector const& states) {
std::vector<storm::storage::sparse::state_type> sortedStates(states.begin(), states.end());
return std::unique_ptr<StatePriorityQueue>(new StaticStatePriorityQueue(sortedStates));
return std::unique_ptr<StatePriorityQueue<ValueType>>(new StaticStatePriorityQueue(sortedStates));
}
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performPrioritizedStateElimination(std::unique_ptr<StatePriorityQueue>& priorityQueue, FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, std::vector<ValueType>& values, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly) {
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performPrioritizedStateElimination(std::unique_ptr<StatePriorityQueue<ValueType>>& priorityQueue, storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, std::vector<ValueType>& values, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly) {
ValueUpdateCallback valueUpdateCallback = [&values] (storm::storage::sparse::state_type const& state, ValueType const& loopProbability) { values[state] = storm::utility::simplify(loopProbability * values[state]); };
PredecessorUpdateCallback predecessorCallback = [&values] (storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) { values[predecessor] = storm::utility::simplify(values[predecessor] + storm::utility::simplify(probability * values[state])); };
boost::optional<PriorityUpdateCallback> priorityUpdateCallback = PriorityUpdateCallback([&transitionMatrix,&backwardTransitions,&values,&priorityQueue] (storm::storage::sparse::state_type const& state) { priorityQueue->update(state, transitionMatrix, backwardTransitions, values); });
boost::optional<PredecessorFilterCallback> predecessorFilterCallback = boost::none;
storm::solver::stateelimination::PrioritizedEliminator<SparseDtmcModelType> stateEliminator(transitionMatrix, backwardTransitions, *priorityQueue, values);
while (priorityQueue->hasNextState()) {
storm::storage::sparse::state_type state = priorityQueue->popNextState();
bool removeForwardTransitions = computeResultsForInitialStatesOnly && !initialStates.get(state);
eliminateState(state, transitionMatrix, backwardTransitions, valueUpdateCallback, predecessorCallback, priorityUpdateCallback, predecessorFilterCallback, removeForwardTransitions);
stateEliminator.eliminateState(state, removeForwardTransitions);
if (removeForwardTransitions) {
values[state] = storm::utility::zero<ValueType>();
}
@ -946,8 +937,8 @@ namespace storm {
}
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performOrdinaryStateElimination(FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
std::unique_ptr<StatePriorityQueue> statePriorities = createStatePriorityQueue(distanceBasedPriorities, transitionMatrix, backwardTransitions, values, subsystem);
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performOrdinaryStateElimination(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
std::unique_ptr<StatePriorityQueue<ValueType>> statePriorities = createStatePriorityQueue(distanceBasedPriorities, transitionMatrix, backwardTransitions, values, subsystem);
std::size_t numberOfStatesToEliminate = statePriorities->size();
STORM_LOG_DEBUG("Eliminating " << numberOfStatesToEliminate << " states using the state elimination technique." << std::endl);
@ -956,7 +947,7 @@ namespace storm {
}
template<typename SparseDtmcModelType>
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performHybridStateElimination(storm::storage::SparseMatrix<ValueType> const& forwardTransitions, FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performHybridStateElimination(storm::storage::SparseMatrix<ValueType> const& forwardTransitions, storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
// When using the hybrid technique, we recursively treat the SCCs up to some size.
std::vector<storm::storage::sparse::state_type> entryStateQueue;
STORM_LOG_DEBUG("Eliminating " << subsystem.size() << " states using the hybrid elimination technique." << std::endl);
@ -966,7 +957,7 @@ namespace storm {
if (storm::settings::sparseDtmcEliminationModelCheckerSettings().isEliminateEntryStatesLastSet()) {
STORM_LOG_DEBUG("Eliminating " << entryStateQueue.size() << " entry states as a last step.");
std::vector<storm::storage::sparse::state_type> sortedStates(entryStateQueue.begin(), entryStateQueue.end());
std::unique_ptr<StatePriorityQueue> queuePriorities = std::unique_ptr<StatePriorityQueue>(new StaticStatePriorityQueue(sortedStates));
std::unique_ptr<StatePriorityQueue<ValueType>> queuePriorities = std::unique_ptr<StatePriorityQueue<ValueType>>(new StaticStatePriorityQueue(sortedStates));
performPrioritizedStateElimination(queuePriorities, transitionMatrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly);
}
STORM_LOG_DEBUG("Eliminated " << subsystem.size() << " states." << std::endl);
@ -976,8 +967,11 @@ namespace storm {
template<typename SparseDtmcModelType>
std::vector<typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::ValueType> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeReachabilityValues(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType>& values, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector<ValueType> const& oneStepProbabilitiesToTarget) {
// Then, we convert the reduced matrix to a more flexible format to be able to perform state elimination more easily.
FlexibleSparseMatrix flexibleMatrix = getFlexibleSparseMatrix(transitionMatrix);
FlexibleSparseMatrix flexibleBackwardTransitions = getFlexibleSparseMatrix(backwardTransitions);
storm::storage::FlexibleSparseMatrix<ValueType> flexibleMatrix(transitionMatrix);
storm::storage::FlexibleSparseMatrix<ValueType> flexibleBackwardTransitions(backwardTransitions);
auto conversionEnd = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point modelCheckingStart = std::chrono::high_resolution_clock::now();
storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder order = storm::settings::sparseDtmcEliminationModelCheckerSettings().getEliminationOrder();
boost::optional<std::vector<uint_fast64_t>> distanceBasedPriorities;
@ -1008,7 +1002,7 @@ namespace storm {
}
template<typename SparseDtmcModelType>
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::treatScc(FlexibleSparseMatrix& matrix, std::vector<ValueType>& values, storm::storage::BitVector const& entryStates, storm::storage::BitVector const& scc, storm::storage::BitVector const& initialStates, storm::storage::SparseMatrix<ValueType> const& forwardTransitions, FlexibleSparseMatrix& backwardTransitions, bool eliminateEntryStates, uint_fast64_t level, uint_fast64_t maximalSccSize, std::vector<storm::storage::sparse::state_type>& entryStateQueue, bool computeResultsForInitialStatesOnly, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::treatScc(storm::storage::FlexibleSparseMatrix<ValueType>& matrix, std::vector<ValueType>& values, storm::storage::BitVector const& entryStates, storm::storage::BitVector const& scc, storm::storage::BitVector const& initialStates, storm::storage::SparseMatrix<ValueType> const& forwardTransitions, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, bool eliminateEntryStates, uint_fast64_t level, uint_fast64_t maximalSccSize, std::vector<storm::storage::sparse::state_type>& entryStateQueue, bool computeResultsForInitialStatesOnly, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
uint_fast64_t maximalDepth = level;
// If the SCCs are large enough, we try to split them further.
@ -1024,7 +1018,7 @@ namespace storm {
storm::storage::BitVector remainingSccs(decomposition.size(), true);
// First, get rid of the trivial SCCs.
storm::storage::BitVector statesInTrivialSccs(matrix.getNumberOfRows());
storm::storage::BitVector statesInTrivialSccs(matrix.getRowCount());
for (uint_fast64_t sccIndex = 0; sccIndex < decomposition.size(); ++sccIndex) {
storm::storage::StronglyConnectedComponent const& scc = decomposition.getBlock(sccIndex);
if (scc.isTrivial()) {
@ -1034,7 +1028,7 @@ namespace storm {
}
}
std::unique_ptr<StatePriorityQueue> statePriorities = createStatePriorityQueue(distanceBasedPriorities, matrix, backwardTransitions, values, statesInTrivialSccs);
std::unique_ptr<StatePriorityQueue<ValueType>> statePriorities = createStatePriorityQueue(distanceBasedPriorities, matrix, backwardTransitions, values, statesInTrivialSccs);
STORM_LOG_TRACE("Eliminating " << statePriorities->size() << " trivial SCCs.");
performPrioritizedStateElimination(statePriorities, matrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly);
STORM_LOG_TRACE("Eliminated all trivial SCCs.");
@ -1064,7 +1058,7 @@ namespace storm {
} else {
// In this case, we perform simple state elimination in the current SCC.
STORM_LOG_TRACE("SCC of size " << scc.getNumberOfSetBits() << " is small enough to be eliminated directly.");
std::unique_ptr<StatePriorityQueue> statePriorities = createStatePriorityQueue(distanceBasedPriorities, matrix, backwardTransitions, values, scc & ~entryStates);
std::unique_ptr<StatePriorityQueue<ValueType>> statePriorities = createStatePriorityQueue(distanceBasedPriorities, matrix, backwardTransitions, values, scc & ~entryStates);
performPrioritizedStateElimination(statePriorities, matrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly);
STORM_LOG_TRACE("Eliminated all states of SCC.");
}
@ -1072,7 +1066,7 @@ namespace storm {
// Finally, eliminate the entry states (if we are required to do so).
if (eliminateEntryStates) {
STORM_LOG_TRACE("Finally, eliminating entry states.");
std::unique_ptr<StatePriorityQueue> naivePriorities = createNaivePriorityQueue(entryStates);
std::unique_ptr<StatePriorityQueue<ValueType>> naivePriorities = createNaivePriorityQueue(entryStates);
performPrioritizedStateElimination(naivePriorities, matrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly);
STORM_LOG_TRACE("Eliminated/added entry states.");
} else {
@ -1085,229 +1079,6 @@ namespace storm {
return maximalDepth;
}
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::eliminateState(storm::storage::sparse::state_type state, FlexibleSparseMatrix& matrix, FlexibleSparseMatrix& backwardTransitions,
ValueUpdateCallback const& callback, PredecessorUpdateCallback const& predecessorCallback,
boost::optional<PriorityUpdateCallback> const& priorityUpdateCallback,
boost::optional<PredecessorFilterCallback> const& predecessorFilterCallback, bool removeForwardTransitions) {
STORM_LOG_TRACE("Eliminating state " << state << ".");
// Start by finding loop probability.
bool hasSelfLoop = false;
ValueType loopProbability = storm::utility::zero<ValueType>();
typename FlexibleSparseMatrix::row_type& currentStateSuccessors = matrix.getRow(state);
for (auto entryIt = currentStateSuccessors.begin(), entryIte = currentStateSuccessors.end(); entryIt != entryIte; ++entryIt) {
if (entryIt->getColumn() >= state) {
if (entryIt->getColumn() == state) {
loopProbability = entryIt->getValue();
hasSelfLoop = true;
// If we do not clear the forward transitions completely, we need to remove the self-loop,
// because we scale all the other outgoing transitions with it anyway.
if (!removeForwardTransitions) {
currentStateSuccessors.erase(entryIt);
}
}
break;
}
}
// Scale all entries in this row with (1 / (1 - loopProbability)) only in case there was a self-loop.
STORM_LOG_TRACE((hasSelfLoop ? "State has self-loop." : "State does not have a self-loop."));
if (hasSelfLoop) {
STORM_LOG_ASSERT(loopProbability != storm::utility::one<ValueType>(), "Must not eliminate state with probability 1 self-loop.");
loopProbability = storm::utility::simplify(storm::utility::one<ValueType>() / (storm::utility::one<ValueType>() - loopProbability));
for (auto& entry : matrix.getRow(state)) {
// Only scale the non-diagonal entries.
if (entry.getColumn() != state) {
entry.setValue(storm::utility::simplify(entry.getValue() * loopProbability));
}
}
callback(state, loopProbability);
}
// Now connect the predecessors of the state being eliminated with its successors.
typename FlexibleSparseMatrix::row_type& currentStatePredecessors = backwardTransitions.getRow(state);
// In case we have a constrained elimination, we need to keep track of the new predecessors.
typename FlexibleSparseMatrix::row_type newCurrentStatePredecessors;
std::vector<typename FlexibleSparseMatrix::row_type> newBackwardProbabilities(currentStateSuccessors.size());
for (auto& backwardProbabilities : newBackwardProbabilities) {
backwardProbabilities.reserve(currentStatePredecessors.size());
}
// Now go through the predecessors and eliminate the ones (satisfying the constraint if given).
for (auto const& predecessorEntry : currentStatePredecessors) {
uint_fast64_t predecessor = predecessorEntry.getColumn();
STORM_LOG_TRACE("Found predecessor " << predecessor << ".");
// Skip the state itself as one of its predecessors.
if (predecessor == state) {
assert(hasSelfLoop);
continue;
}
// Skip the state if the elimination is constrained, but the predecessor is not in the constraint.
if (predecessorFilterCallback && !predecessorFilterCallback.get()(predecessor)) {
newCurrentStatePredecessors.emplace_back(predecessorEntry);
STORM_LOG_TRACE("Not eliminating predecessor " << predecessor << ", because it does not fit the filter.");
continue;
}
STORM_LOG_TRACE("Eliminating predecessor " << predecessor << ".");
// First, find the probability with which the predecessor can move to the current state, because
// the forward probabilities of the state to be eliminated need to be scaled with this factor.
typename FlexibleSparseMatrix::row_type& predecessorForwardTransitions = matrix.getRow(predecessor);
typename FlexibleSparseMatrix::row_type::iterator multiplyElement = std::find_if(predecessorForwardTransitions.begin(), predecessorForwardTransitions.end(), [&](storm::storage::MatrixEntry<typename FlexibleSparseMatrix::index_type, typename FlexibleSparseMatrix::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(storm::utility::zero<ValueType>());
// At this point, we need to update the (forward) transitions of the predecessor.
typename FlexibleSparseMatrix::row_type::iterator first1 = predecessorForwardTransitions.begin();
typename FlexibleSparseMatrix::row_type::iterator last1 = predecessorForwardTransitions.end();
typename FlexibleSparseMatrix::row_type::iterator first2 = currentStateSuccessors.begin();
typename FlexibleSparseMatrix::row_type::iterator last2 = currentStateSuccessors.end();
typename FlexibleSparseMatrix::row_type newSuccessors;
newSuccessors.reserve((last1 - first1) + (last2 - first2));
std::insert_iterator<typename FlexibleSparseMatrix::row_type> result(newSuccessors, newSuccessors.end());
uint_fast64_t successorOffsetInNewBackwardTransitions = 0;
// 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::index_type, typename FlexibleSparseMatrix::value_type> const& a) { return a.getColumn() != state; } );
break;
}
if (first2->getColumn() < first1->getColumn()) {
auto successorEntry = storm::utility::simplify(std::move(*first2 * multiplyFactor));
*result = successorEntry;
newBackwardProbabilities[successorOffsetInNewBackwardTransitions].emplace_back(predecessor, successorEntry.getValue());
++first2;
++successorOffsetInNewBackwardTransitions;
} else if (first1->getColumn() < first2->getColumn()) {
*result = *first1;
++first1;
} else {
auto probability = storm::utility::simplify(first1->getValue() + storm::utility::simplify(multiplyFactor * first2->getValue()));
*result = storm::storage::MatrixEntry<typename FlexibleSparseMatrix::index_type, typename FlexibleSparseMatrix::value_type>(first1->getColumn(), probability);
newBackwardProbabilities[successorOffsetInNewBackwardTransitions].emplace_back(predecessor, probability);
++first1;
++first2;
++successorOffsetInNewBackwardTransitions;
}
}
for (; first2 != last2; ++first2) {
if (first2->getColumn() != state) {
auto stateProbability = storm::utility::simplify(std::move(*first2 * multiplyFactor));
*result = stateProbability;
newBackwardProbabilities[successorOffsetInNewBackwardTransitions].emplace_back(predecessor, stateProbability.getValue());
++successorOffsetInNewBackwardTransitions;
}
}
// Now move the new transitions in place.
predecessorForwardTransitions = std::move(newSuccessors);
STORM_LOG_TRACE("Fixed new next-state probabilities of predecessor state " << predecessor << ".");
predecessorCallback(predecessor, multiplyFactor, state);
if (priorityUpdateCallback) {
STORM_LOG_TRACE("Updating priority of predecessor.");
priorityUpdateCallback.get()(predecessor);
}
}
// Finally, we need to add the predecessor to the set of predecessors of every successor.
uint_fast64_t successorOffsetInNewBackwardTransitions = 0;
for (auto const& successorEntry : currentStateSuccessors) {
if (successorEntry.getColumn() == state) {
continue;
}
typename FlexibleSparseMatrix::row_type& successorBackwardTransitions = backwardTransitions.getRow(successorEntry.getColumn());
// Delete the current state as a predecessor of the successor state only if we are going to remove the
// current state's forward transitions.
if (removeForwardTransitions) {
typename FlexibleSparseMatrix::row_type::iterator elimIt = std::find_if(successorBackwardTransitions.begin(), successorBackwardTransitions.end(), [&](storm::storage::MatrixEntry<typename FlexibleSparseMatrix::index_type, typename FlexibleSparseMatrix::value_type> const& a) { return a.getColumn() == state; });
STORM_LOG_ASSERT(elimIt != successorBackwardTransitions.end(), "Expected a proper backward transition from " << successorEntry.getColumn() << " to " << state << ", but found none.");
successorBackwardTransitions.erase(elimIt);
}
typename FlexibleSparseMatrix::row_type::iterator first1 = successorBackwardTransitions.begin();
typename FlexibleSparseMatrix::row_type::iterator last1 = successorBackwardTransitions.end();
typename FlexibleSparseMatrix::row_type::iterator first2 = newBackwardProbabilities[successorOffsetInNewBackwardTransitions].begin();
typename FlexibleSparseMatrix::row_type::iterator last2 = newBackwardProbabilities[successorOffsetInNewBackwardTransitions].end();
typename FlexibleSparseMatrix::row_type newPredecessors;
newPredecessors.reserve((last1 - first1) + (last2 - first2));
std::insert_iterator<typename FlexibleSparseMatrix::row_type> result(newPredecessors, newPredecessors.end());
for (; first1 != last1; ++result) {
if (first2 == last2) {
std::copy(first1, last1, result);
break;
}
if (first2->getColumn() < first1->getColumn()) {
if (first2->getColumn() != state) {
*result = *first2;
}
++first2;
} else if (first1->getColumn() == first2->getColumn()) {
if (estimateComplexity(first1->getValue()) > estimateComplexity(first2->getValue())) {
*result = *first1;
} else {
*result = *first2;
}
++first1;
++first2;
} else {
*result = *first1;
++first1;
}
}
if (predecessorFilterCallback) {
std::copy_if(first2, last2, result, [&] (storm::storage::MatrixEntry<typename FlexibleSparseMatrix::index_type, typename FlexibleSparseMatrix::value_type> const& a) { return a.getColumn() != state && predecessorFilterCallback.get()(a.getColumn()); });
} else {
std::copy_if(first2, last2, result, [&] (storm::storage::MatrixEntry<typename FlexibleSparseMatrix::index_type, typename FlexibleSparseMatrix::value_type> const& a) { return a.getColumn() != state; });
}
// Now move the new predecessors in place.
successorBackwardTransitions = std::move(newPredecessors);
++successorOffsetInNewBackwardTransitions;
}
STORM_LOG_TRACE("Fixed predecessor lists of successor states.");
if (removeForwardTransitions) {
// Clear the eliminated row to reduce memory consumption.
currentStateSuccessors.clear();
currentStateSuccessors.shrink_to_fit();
}
if (predecessorFilterCallback) {
currentStatePredecessors = std::move(newCurrentStatePredecessors);
} else {
currentStatePredecessors.clear();
currentStatePredecessors.shrink_to_fit();
}
}
template<typename SparseDtmcModelType>
std::vector<uint_fast64_t> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::getDistanceBasedPriorities(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& transitionMatrixTransposed, storm::storage::BitVector const& initialStates, std::vector<ValueType> const& oneStepProbabilities, bool forward, bool reverse) {
std::vector<uint_fast64_t> statePriorities(transitionMatrix.getRowCount());
@ -1356,111 +1127,7 @@ namespace storm {
}
template<typename SparseDtmcModelType>
SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::FlexibleSparseMatrix(index_type rows) : data(rows) {
// Intentionally left empty.
}
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::reserveInRow(index_type row, index_type numberOfElements) {
this->data[row].reserve(numberOfElements);
}
template<typename SparseDtmcModelType>
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::row_type& SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::getRow(index_type index) {
return this->data[index];
}
template<typename SparseDtmcModelType>
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::row_type const& SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::getRow(index_type index) const {
return this->data[index];
}
template<typename SparseDtmcModelType>
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::index_type SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::getNumberOfRows() const {
return this->data.size();
}
template<typename SparseDtmcModelType>
bool SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::hasSelfLoop(storm::storage::sparse::state_type state) {
for (auto const& entry : this->getRow(state)) {
if (entry.getColumn() < state) {
continue;
} else if (entry.getColumn() > state) {
return false;
} else if (entry.getColumn() == state) {
return true;
}
}
return false;
}
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::print() const {
for (uint_fast64_t index = 0; index < this->data.size(); ++index) {
std::cout << index << " - ";
for (auto const& element : this->getRow(index)) {
std::cout << "(" << element.getColumn() << ", " << element.getValue() << ") ";
}
std::cout << std::endl;
}
}
template<typename SparseDtmcModelType>
bool SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::empty() const {
for (auto const& row : this->data) {
if (!row.empty()) {
return false;
}
}
return true;
}
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::filter(storm::storage::BitVector const& rowFilter, storm::storage::BitVector const& columnFilter) {
for (uint_fast64_t rowIndex = 0; rowIndex < this->data.size(); ++rowIndex) {
auto& row = this->data[rowIndex];
if (!rowFilter.get(rowIndex)) {
row.clear();
row.shrink_to_fit();
continue;
}
row_type newRow;
for (auto const& element : row) {
if (columnFilter.get(element.getColumn())) {
newRow.push_back(element);
}
}
row = std::move(newRow);
}
}
template<typename SparseDtmcModelType>
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix SparseDtmcEliminationModelChecker<SparseDtmcModelType>::getFlexibleSparseMatrix(storm::storage::SparseMatrix<ValueType> const& matrix, bool setAllValuesToOne) {
FlexibleSparseMatrix flexibleMatrix(matrix.getRowCount());
for (typename FlexibleSparseMatrix::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 the probability is zero, we skip this entry.
if (storm::utility::isZero(element.getValue())) {
continue;
}
if (setAllValuesToOne) {
flexibleMatrix.getRow(rowIndex).emplace_back(element.getColumn(), storm::utility::one<ValueType>());
} else {
flexibleMatrix.getRow(rowIndex).emplace_back(element);
}
}
}
return flexibleMatrix;
}
template<typename SparseDtmcModelType>
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeStatePenalty(storm::storage::sparse::state_type const& state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeStatePenalty(storm::storage::sparse::state_type const& state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
uint_fast64_t penalty = 0;
bool hasParametricSelfLoop = false;
@ -1487,17 +1154,17 @@ namespace storm {
}
template<typename SparseDtmcModelType>
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeStatePenaltyRegularExpression(storm::storage::sparse::state_type const& state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeStatePenaltyRegularExpression(storm::storage::sparse::state_type const& state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
return backwardTransitions.getRow(state).size() * transitionMatrix.getRow(state).size();
}
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::StatePriorityQueue::update(storm::storage::sparse::state_type, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
template<typename ValueType>
void StatePriorityQueue<ValueType>::update(storm::storage::sparse::state_type, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
// Intentionally left empty.
}
template<typename SparseDtmcModelType>
SparseDtmcEliminationModelChecker<SparseDtmcModelType>::StaticStatePriorityQueue::StaticStatePriorityQueue(std::vector<storm::storage::sparse::state_type> const& sortedStates) : StatePriorityQueue(), sortedStates(sortedStates), currentPosition(0) {
SparseDtmcEliminationModelChecker<SparseDtmcModelType>::StaticStatePriorityQueue::StaticStatePriorityQueue(std::vector<storm::storage::sparse::state_type> const& sortedStates) : StatePriorityQueue<ValueType>(), sortedStates(sortedStates), currentPosition(0) {
// Intentionally left empty.
}
@ -1518,7 +1185,7 @@ namespace storm {
}
template<typename SparseDtmcModelType>
SparseDtmcEliminationModelChecker<SparseDtmcModelType>::DynamicPenaltyStatePriorityQueue::DynamicPenaltyStatePriorityQueue(std::vector<std::pair<storm::storage::sparse::state_type, uint_fast64_t>> const& sortedStatePenaltyPairs, PenaltyFunctionType const& penaltyFunction) : StatePriorityQueue(), priorityQueue(), stateToPriorityMapping(), penaltyFunction(penaltyFunction) {
SparseDtmcEliminationModelChecker<SparseDtmcModelType>::DynamicPenaltyStatePriorityQueue::DynamicPenaltyStatePriorityQueue(std::vector<std::pair<storm::storage::sparse::state_type, uint_fast64_t>> const& sortedStatePenaltyPairs, PenaltyFunctionType const& penaltyFunction) : StatePriorityQueue<ValueType>(), priorityQueue(), stateToPriorityMapping(), penaltyFunction(penaltyFunction) {
// Insert all state-penalty pairs into our priority queue.
for (auto const& statePenalty : sortedStatePenaltyPairs) {
priorityQueue.insert(priorityQueue.end(), statePenalty);
@ -1545,7 +1212,7 @@ namespace storm {
}
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::DynamicPenaltyStatePriorityQueue::update(storm::storage::sparse::state_type state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::DynamicPenaltyStatePriorityQueue::update(storm::storage::sparse::state_type state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
// First, we need to find the priority until now.
auto priorityIt = stateToPriorityMapping.find(state);
@ -1574,8 +1241,8 @@ namespace storm {
}
template<typename SparseDtmcModelType>
bool SparseDtmcEliminationModelChecker<SparseDtmcModelType>::checkConsistent(FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions) {
for (uint_fast64_t forwardIndex = 0; forwardIndex < transitionMatrix.getNumberOfRows(); ++forwardIndex) {
bool SparseDtmcEliminationModelChecker<SparseDtmcModelType>::checkConsistent(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions) {
for (uint_fast64_t forwardIndex = 0; forwardIndex < transitionMatrix.getRowCount(); ++forwardIndex) {
for (auto const& forwardEntry : transitionMatrix.getRow(forwardIndex)) {
if (forwardEntry.getColumn() == forwardIndex) {
continue;
@ -1596,9 +1263,11 @@ namespace storm {
return true;
}
template class StatePriorityQueue<double>;
template class SparseDtmcEliminationModelChecker<storm::models::sparse::Dtmc<double>>;
#ifdef STORM_HAVE_CARL
template class StatePriorityQueue<storm::RationalFunction>;
template class SparseDtmcEliminationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>>;
#endif
} // namespace modelchecker

95
src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h

@ -2,6 +2,7 @@
#define STORM_MODELCHECKER_REACHABILITY_SPARSEDTMCELIMINATIONMODELCHECKER_H_
#include "src/storage/sparse/StateType.h"
#include "src/storage/FlexibleSparseMatrix.h"
#include "src/models/sparse/Dtmc.h"
#include "src/modelchecker/propositional/SparsePropositionalModelChecker.h"
#include "src/utility/constants.h"
@ -9,11 +10,25 @@
namespace storm {
namespace modelchecker {
template<typename ValueType>
uint_fast64_t estimateComplexity(ValueType const& value);
template<typename ValueType>
class StatePriorityQueue {
public:
virtual bool hasNextState() const = 0;
virtual storm::storage::sparse::state_type popNextState() = 0;
virtual void update(storm::storage::sparse::state_type state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
virtual std::size_t size() const = 0;
};
template<typename SparseDtmcModelType>
class SparseDtmcEliminationModelChecker : public SparsePropositionalModelChecker<SparseDtmcModelType> {
public:
typedef typename SparseDtmcModelType::ValueType ValueType;
typedef typename SparseDtmcModelType::RewardModelType RewardModelType;
typedef typename storm::storage::FlexibleSparseMatrix<ValueType>::row_type FlexibleRowType;
typedef typename FlexibleRowType::iterator FlexibleRowIterator;
/*!
* Creates an elimination-based model checker for the given model.
@ -37,51 +52,8 @@ namespace storm {
static std::vector<ValueType> computeReachabilityRewards(storm::storage::SparseMatrix<ValueType> const& probabilityMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& targetStates, std::vector<ValueType>& stateRewardValues, bool computeForInitialStatesOnly);
private:
class FlexibleSparseMatrix {
public:
typedef uint_fast64_t index_type;
typedef ValueType value_type;
typedef std::vector<storm::storage::MatrixEntry<index_type, value_type>> row_type;
typedef typename row_type::iterator iterator;
typedef typename row_type::const_iterator const_iterator;
FlexibleSparseMatrix() = default;
FlexibleSparseMatrix(index_type rows);
void reserveInRow(index_type row, index_type numberOfElements);
row_type& getRow(index_type);
row_type const& getRow(index_type) const;
index_type getNumberOfRows() const;
void print() const;
bool empty() const;
void filter(storm::storage::BitVector const& rowFilter, storm::storage::BitVector const& columnFilter);
/*!
* Checks whether the given state has a self-loop with an arbitrary probability in the probability matrix.
*
* @param state The state for which to check whether it possesses a self-loop.
* @return True iff the given state has a self-loop with an arbitrary probability in the probability matrix.
*/
bool hasSelfLoop(storm::storage::sparse::state_type state);
private:
std::vector<row_type> data;
};
class StatePriorityQueue {
public:
virtual bool hasNextState() const = 0;
virtual storm::storage::sparse::state_type popNextState() = 0;
virtual void update(storm::storage::sparse::state_type state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
virtual std::size_t size() const = 0;
};
class StaticStatePriorityQueue : public StatePriorityQueue {
class StaticStatePriorityQueue : public StatePriorityQueue<ValueType> {
public:
StaticStatePriorityQueue(std::vector<storm::storage::sparse::state_type> const& sortedStates);
@ -100,15 +72,15 @@ namespace storm {
}
};
typedef std::function<uint_fast64_t (storm::storage::sparse::state_type const& state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities)> PenaltyFunctionType;
typedef std::function<uint_fast64_t (storm::storage::sparse::state_type const& state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities)> PenaltyFunctionType;
class DynamicPenaltyStatePriorityQueue : public StatePriorityQueue {
class DynamicPenaltyStatePriorityQueue : public StatePriorityQueue<ValueType> {
public:
DynamicPenaltyStatePriorityQueue(std::vector<std::pair<storm::storage::sparse::state_type, uint_fast64_t>> const& sortedStatePenaltyPairs, PenaltyFunctionType const& penaltyFunction);
virtual bool hasNextState() const override;
virtual storm::storage::sparse::state_type popNextState() override;
virtual void update(storm::storage::sparse::state_type state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) override;
virtual void update(storm::storage::sparse::state_type state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) override;
virtual std::size_t size() const override;
private:
@ -121,38 +93,29 @@ namespace storm {
static std::vector<ValueType> computeReachabilityValues(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType>& values, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector<ValueType> const& oneStepProbabilitiesToTarget);
static std::unique_ptr<StatePriorityQueue> createStatePriorityQueue(boost::optional<std::vector<uint_fast64_t>> const& stateDistances, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType>& oneStepProbabilities, storm::storage::BitVector const& states);
static std::unique_ptr<StatePriorityQueue> createNaivePriorityQueue(storm::storage::BitVector const& states);
static void performPrioritizedStateElimination(std::unique_ptr<StatePriorityQueue>& priorityQueue, FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, std::vector<ValueType>& values, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly);
static void performOrdinaryStateElimination(FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<ValueType>>& additionalStateValues, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
static std::unique_ptr<StatePriorityQueue<ValueType>> createStatePriorityQueue(boost::optional<std::vector<uint_fast64_t>> const& stateDistances, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType>& oneStepProbabilities, storm::storage::BitVector const& states);
static void performOrdinaryStateElimination(FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
static std::unique_ptr<StatePriorityQueue<ValueType>> createNaivePriorityQueue(storm::storage::BitVector const& states);
static uint_fast64_t performHybridStateElimination(storm::storage::SparseMatrix<ValueType> const& forwardTransitions, FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
static void performPrioritizedStateElimination(std::unique_ptr<StatePriorityQueue<ValueType>>& priorityQueue, storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, std::vector<ValueType>& values, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly);
static uint_fast64_t treatScc(FlexibleSparseMatrix& matrix, std::vector<ValueType>& values, storm::storage::BitVector const& entryStates, storm::storage::BitVector const& scc, storm::storage::BitVector const& initialStates, storm::storage::SparseMatrix<ValueType> const& forwardTransitions, FlexibleSparseMatrix& backwardTransitions, bool eliminateEntryStates, uint_fast64_t level, uint_fast64_t maximalSccSize, std::vector<storm::storage::sparse::state_type>& entryStateQueue, bool computeResultsForInitialStatesOnly, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities = boost::none);
static void performOrdinaryStateElimination(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<ValueType>>& additionalStateValues, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
static FlexibleSparseMatrix getFlexibleSparseMatrix(storm::storage::SparseMatrix<ValueType> const& matrix, bool setAllValuesToOne = false);
static void performOrdinaryStateElimination(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
typedef std::function<void (storm::storage::sparse::state_type const& state, ValueType const& loopProbability)> ValueUpdateCallback;
typedef std::function<void (storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state)> PredecessorUpdateCallback;
typedef std::function<void (storm::storage::sparse::state_type const& state)> PriorityUpdateCallback;
typedef std::function<bool (storm::storage::sparse::state_type const& state)> PredecessorFilterCallback;
static uint_fast64_t performHybridStateElimination(storm::storage::SparseMatrix<ValueType> const& forwardTransitions, storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
static void eliminateState(storm::storage::sparse::state_type state, FlexibleSparseMatrix& matrix, FlexibleSparseMatrix& backwardTransitions, ValueUpdateCallback const& valueUpdateCallback, PredecessorUpdateCallback const& predecessorCallback, boost::optional<PriorityUpdateCallback> const& priorityUpdateCallback = boost::none, boost::optional<PredecessorFilterCallback> const& predecessorFilterCallback = boost::none, bool removeForwardTransitions = true);
static uint_fast64_t treatScc(storm::storage::FlexibleSparseMatrix<ValueType>& matrix, std::vector<ValueType>& values, storm::storage::BitVector const& entryStates, storm::storage::BitVector const& scc, storm::storage::BitVector const& initialStates, storm::storage::SparseMatrix<ValueType> const& forwardTransitions, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, bool eliminateEntryStates, uint_fast64_t level, uint_fast64_t maximalSccSize, std::vector<storm::storage::sparse::state_type>& entryStateQueue, bool computeResultsForInitialStatesOnly, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities = boost::none);
static std::vector<uint_fast64_t> getDistanceBasedPriorities(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& transitionMatrixTransposed, storm::storage::BitVector const& initialStates, std::vector<ValueType> const& oneStepProbabilities, bool forward, bool reverse);
static std::vector<std::size_t> getStateDistances(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& transitionMatrixTransposed, storm::storage::BitVector const& initialStates, std::vector<ValueType> const& oneStepProbabilities, bool forward);
static uint_fast64_t computeStatePenalty(storm::storage::sparse::state_type const& state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
static uint_fast64_t computeStatePenalty(storm::storage::sparse::state_type const& state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
static uint_fast64_t computeStatePenaltyRegularExpression(storm::storage::sparse::state_type const& state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
static uint_fast64_t computeStatePenaltyRegularExpression(storm::storage::sparse::state_type const& state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
static bool checkConsistent(FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions);
static bool checkConsistent(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions);
};

62
src/solver/EliminationLinearEquationSolver.cpp

@ -0,0 +1,62 @@
#include "src/solver/EliminationLinearEquationSolver.h"
#include "src/utility/vector.h"
namespace storm {
namespace solver {
template<typename ValueType>
EliminationLinearEquationSolver<ValueType>::EliminationLinearEquationSolver(storm::storage::SparseMatrix<ValueType> const& A) : A(A) {
// Intentionally left empty.
}
template<typename ValueType>
void EliminationLinearEquationSolver<ValueType>::solveEquationSystem(std::vector<ValueType>& x, std::vector<ValueType> const& b, std::vector<ValueType>* multiplyResult) const {
// TODO: implement state-elimination here.
}
template<typename ValueType>
void EliminationLinearEquationSolver<ValueType>::performMatrixVectorMultiplication(std::vector<ValueType>& x, std::vector<ValueType> const* b, uint_fast64_t n, std::vector<ValueType>* multiplyResult) const {
// Set up some temporary variables so that we can just swap pointers instead of copying the result after
// each iteration.
std::vector<ValueType>* currentX = &x;
bool multiplyResultProvided = true;
std::vector<ValueType>* nextX = multiplyResult;
if (nextX == nullptr) {
nextX = new std::vector<ValueType>(x.size());
multiplyResultProvided = false;
}
std::vector<ValueType> const* copyX = nextX;
// Now perform matrix-vector multiplication as long as we meet the bound.
for (uint_fast64_t i = 0; i < n; ++i) {
A.multiplyWithVector(*currentX, *nextX);
std::swap(nextX, currentX);
// If requested, add an offset to the current result vector.
if (b != nullptr) {
storm::utility::vector::addVectors(*currentX, *b, *currentX);
}
}
// If we performed an odd number of repetitions, we need to swap the contents of currentVector and x,
// because the output is supposed to be stored in the input vector x.
if (currentX == copyX) {
std::swap(x, *currentX);
}
// If the vector for the temporary multiplication result was not provided, we need to delete it.
if (!multiplyResultProvided) {
delete copyX;
}
}
template class EliminationLinearEquationSolver<double>;
// TODO: make this work with the proper implementation of solveEquationSystem.
template class EliminationLinearEquationSolver<storm::RationalNumber>;
template class EliminationLinearEquationSolver<storm::RationalFunction>;
}
}

34
src/solver/EliminationLinearEquationSolver.h

@ -0,0 +1,34 @@
#ifndef STORM_SOLVER_ELIMINATIONLINEAREQUATIONSOLVER_H_
#define STORM_SOLVER_ELIMINATIONLINEAREQUATIONSOLVER_H_
#include "src/solver/LinearEquationSolver.h"
namespace storm {
namespace solver {
/*!
* A class that uses gaussian elimination to implement the LinearEquationSolver interface. In particular
*/
template<typename ValueType>
class EliminationLinearEquationSolver : public LinearEquationSolver<ValueType> {
public:
/*!
* Constructs a linear equation solver.
*
* @param A The matrix defining the coefficients of the linear equation system.
*/
EliminationLinearEquationSolver(storm::storage::SparseMatrix<ValueType> const& A);
virtual void solveEquationSystem(std::vector<ValueType>& x, std::vector<ValueType> const& b, std::vector<ValueType>* multiplyResult = nullptr) const override;
virtual void performMatrixVectorMultiplication(std::vector<ValueType>& x, std::vector<ValueType> const* b, uint_fast64_t n = 1, std::vector<ValueType>* multiplyResult = nullptr) const override;
private:
// A reference to the original matrix used for this equation solver.
storm::storage::SparseMatrix<ValueType> const& A;
};
}
}
#endif /* STORM_SOLVER_ELIMINATIONLINEAREQUATIONSOLVER_H_ */

2
src/solver/NativeLinearEquationSolver.h

@ -10,6 +10,7 @@ namespace storm {
enum class NativeLinearEquationSolverSolutionMethod {
Jacobi, GaussSeidel, SOR
};
/*!
* A class that uses StoRM's native matrix operations to implement the LinearEquationSolver interface.
*/
@ -17,7 +18,6 @@ namespace storm {
class NativeLinearEquationSolver : public LinearEquationSolver<ValueType> {
public:
/*!
* Constructs a linear equation solver with parameters being set according to the settings object.
*

53
src/solver/stateelimination/ConditionalEliminator.cpp

@ -0,0 +1,53 @@
#include "src/solver/stateelimination/ConditionalEliminator.h"
namespace storm {
namespace solver {
namespace stateelimination {
template<typename SparseModelType>
ConditionalEliminator<SparseModelType>::ConditionalEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, std::vector<ValueType>& oneStepProbabilities, storm::storage::BitVector& phiStates, storm::storage::BitVector& psiStates) : StateEliminator<SparseModelType>(transitionMatrix, backwardTransitions), oneStepProbabilities(oneStepProbabilities), phiStates(phiStates), psiStates(psiStates), specificState(NONE) {
}
template<typename SparseModelType>
void ConditionalEliminator<SparseModelType>::updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability) {
oneStepProbabilities[state] = storm::utility::simplify(loopProbability * oneStepProbabilities[state]);
}
template<typename SparseModelType>
void ConditionalEliminator<SparseModelType>::updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) {
oneStepProbabilities[predecessor] = storm::utility::simplify(oneStepProbabilities[predecessor] * storm::utility::simplify(probability * oneStepProbabilities[state]));
}
template<typename SparseModelType>
void ConditionalEliminator<SparseModelType>::updatePriority(storm::storage::sparse::state_type const& state) {
// Do nothing
}
template<typename SparseModelType>
bool ConditionalEliminator<SparseModelType>::filterPredecessor(storm::storage::sparse::state_type const& state) {
// TODO find better solution than flag
switch (specificState) {
case PHI:
return phiStates.get(state);
case PSI:
return psiStates.get(state);
case NONE:
assert(false);
}
}
template<typename SparseModelType>
bool ConditionalEliminator<SparseModelType>::isFilterPredecessor() const {
return true;
}
template class ConditionalEliminator<storm::models::sparse::Dtmc<double>>;
#ifdef STORM_HAVE_CARL
template class ConditionalEliminator<storm::models::sparse::Dtmc<storm::RationalFunction>>;
#endif
} // namespace stateelimination
} // namespace storage
} // namespace storm

53
src/solver/stateelimination/ConditionalEliminator.h

@ -0,0 +1,53 @@
#ifndef STORM_SOLVER_STATEELIMINATION_CONDITIONALELIMINATOR_H_
#define STORM_SOLVER_STATEELIMINATION_CONDITIONALELIMINATOR_H_
#include "src/solver/stateelimination/StateEliminator.h"
#include "src/storage/BitVector.h"
namespace storm {
namespace solver {
namespace stateelimination {
template<typename SparseModelType>
class ConditionalEliminator : public StateEliminator<SparseModelType> {
typedef typename SparseModelType::ValueType ValueType;
enum SpecificState { NONE, PHI, PSI};
public:
ConditionalEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, std::vector<ValueType>& oneStepProbabilities, storm::storage::BitVector& phiStates, storm::storage::BitVector& psiStates);
// Instantiaton of Virtual methods
void updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability) override;
void updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) override;
void updatePriority(storm::storage::sparse::state_type const& state) override;
bool filterPredecessor(storm::storage::sparse::state_type const& state) override;
bool isFilterPredecessor() const override;
void setStatePsi() {
specificState = PSI;
}
void setStatePhi() {
specificState = PHI;
}
void clearState() {
specificState = NONE;
}
private:
std::vector<ValueType>& oneStepProbabilities;
storm::storage::BitVector& phiStates;
storm::storage::BitVector& psiStates;
SpecificState specificState;
};
} // namespace stateelimination
} // namespace storage
} // namespace storm
#endif // STORM_SOLVER_STATEELIMINATION_CONDITIONALELIMINATOR_H_

47
src/solver/stateelimination/LongRunAverageEliminator.cpp

@ -0,0 +1,47 @@
#include "src/solver/stateelimination/LongRunAverageEliminator.h"
namespace storm {
namespace solver {
namespace stateelimination {
template<typename SparseModelType>
LongRunAverageEliminator<SparseModelType>::LongRunAverageEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::modelchecker::StatePriorityQueue<ValueType>& priorityQueue, std::vector<ValueType>& stateValues, std::vector<ValueType>& averageTimeInStates) : StateEliminator<SparseModelType>(transitionMatrix, backwardTransitions), priorityQueue(priorityQueue), stateValues(stateValues), averageTimeInStates(averageTimeInStates) {
}
template<typename SparseModelType>
void LongRunAverageEliminator<SparseModelType>::updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability) {
stateValues[state] = storm::utility::simplify(loopProbability * stateValues[state]);
averageTimeInStates[state] = storm::utility::simplify(loopProbability * averageTimeInStates[state]);
}
template<typename SparseModelType>
void LongRunAverageEliminator<SparseModelType>::updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) {
stateValues[predecessor] = storm::utility::simplify(stateValues[predecessor] + storm::utility::simplify(probability * stateValues[state]));
averageTimeInStates[predecessor] = storm::utility::simplify(averageTimeInStates[predecessor] + storm::utility::simplify(probability * averageTimeInStates[state]));
}
template<typename SparseModelType>
void LongRunAverageEliminator<SparseModelType>::updatePriority(storm::storage::sparse::state_type const& state) {
priorityQueue.update(state, StateEliminator<SparseModelType>::transitionMatrix, StateEliminator<SparseModelType>::backwardTransitions, stateValues);
}
template<typename SparseModelType>
bool LongRunAverageEliminator<SparseModelType>::filterPredecessor(storm::storage::sparse::state_type const& state) {
assert(false);
}
template<typename SparseModelType>
bool LongRunAverageEliminator<SparseModelType>::isFilterPredecessor() const {
return false;
}
template class LongRunAverageEliminator<storm::models::sparse::Dtmc<double>>;
#ifdef STORM_HAVE_CARL
template class LongRunAverageEliminator<storm::models::sparse::Dtmc<storm::RationalFunction>>;
#endif
} // namespace stateelimination
} // namespace storage
} // namespace storm

36
src/solver/stateelimination/LongRunAverageEliminator.h

@ -0,0 +1,36 @@
#ifndef STORM_SOLVER_STATEELIMINATION_LONGRUNAVERAGEELIMINATOR_H_
#define STORM_SOLVER_STATEELIMINATION_LONGRUNAVERAGEELIMINATOR_H_
#include "src/solver/stateelimination/StateEliminator.h"
namespace storm {
namespace solver {
namespace stateelimination {
template<typename SparseModelType>
class LongRunAverageEliminator : public StateEliminator<SparseModelType> {
typedef typename SparseModelType::ValueType ValueType;
public:
LongRunAverageEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::modelchecker::StatePriorityQueue<ValueType>& priorityQueue, std::vector<ValueType>& stateValues, std::vector<ValueType>& averageTimeInStates);
// Instantiaton of Virtual methods
void updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability) override;
void updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) override;
void updatePriority(storm::storage::sparse::state_type const& state) override;
bool filterPredecessor(storm::storage::sparse::state_type const& state) override;
bool isFilterPredecessor() const override;
private:
storm::modelchecker::StatePriorityQueue<ValueType>& priorityQueue;
std::vector<ValueType>& stateValues;
std::vector<ValueType>& averageTimeInStates;
};
} // namespace stateelimination
} // namespace storage
} // namespace storm
#endif // STORM_SOLVER_STATEELIMINATION_LONGRUNAVERAGEELIMINATOR_H_

45
src/solver/stateelimination/PrioritizedEliminator.cpp

@ -0,0 +1,45 @@
#include "src/solver/stateelimination/PrioritizedEliminator.h"
namespace storm {
namespace solver {
namespace stateelimination {
template<typename SparseModelType>
PrioritizedEliminator<SparseModelType>::PrioritizedEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::modelchecker::StatePriorityQueue<ValueType> priorityQueue, std::vector<ValueType>& stateValues) : StateEliminator<SparseModelType>(transitionMatrix, backwardTransitions), priorityQueue(priorityQueue), stateValues(stateValues) {
}
template<typename SparseModelType>
void PrioritizedEliminator<SparseModelType>::updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability) {
stateValues[state] = storm::utility::simplify(loopProbability * stateValues[state]);
}
template<typename SparseModelType>
void PrioritizedEliminator<SparseModelType>::updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) {
stateValues[predecessor] = storm::utility::simplify(stateValues[predecessor] + storm::utility::simplify(probability * stateValues[state]));
}
template<typename SparseModelType>
void PrioritizedEliminator<SparseModelType>::updatePriority(storm::storage::sparse::state_type const& state) {
priorityQueue.update(state, StateEliminator<SparseModelType>::transitionMatrix, StateEliminator<SparseModelType>::backwardTransitions, stateValues);
}
template<typename SparseModelType>
bool PrioritizedEliminator<SparseModelType>::filterPredecessor(storm::storage::sparse::state_type const& state) {
assert(false);
}
template<typename SparseModelType>
bool PrioritizedEliminator<SparseModelType>::isFilterPredecessor() const {
return false;
}
template class PrioritizedEliminator<storm::models::sparse::Dtmc<double>>;
#ifdef STORM_HAVE_CARL
template class PrioritizedEliminator<storm::models::sparse::Dtmc<storm::RationalFunction>>;
#endif
} // namespace stateelimination
} // namespace storage
} // namespace storm

34
src/solver/stateelimination/PrioritizedEliminator.h

@ -0,0 +1,34 @@
#ifndef STORM_SOLVER_STATEELIMINATION_PRIORITIZEDELIMINATOR_H_
#define STORM_SOLVER_STATEELIMINATION_PRIORITIZEDELIMINATOR_H_
#include "src/solver/stateelimination/StateEliminator.h"
namespace storm {
namespace solver {
namespace stateelimination {
template<typename SparseModelType>
class PrioritizedEliminator : public StateEliminator<SparseModelType> {
typedef typename SparseModelType::ValueType ValueType;
public:
PrioritizedEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::modelchecker::StatePriorityQueue<ValueType> priorityQueue, std::vector<ValueType>& stateValues);
// Instantiaton of Virtual methods
void updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability) override;
void updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) override;
void updatePriority(storm::storage::sparse::state_type const& state) override;
bool filterPredecessor(storm::storage::sparse::state_type const& state) override;
bool isFilterPredecessor() const override;
private:
storm::modelchecker::StatePriorityQueue<ValueType>& priorityQueue;
std::vector<ValueType>& stateValues;
};
} // namespace stateelimination
} // namespace storage
} // namespace storm
#endif // STORM_SOLVER_STATEELIMINATION_PRIORITIZEDELIMINATOR_H_

259
src/solver/stateelimination/StateEliminator.cpp

@ -0,0 +1,259 @@
#include "src/solver/stateelimination/StateEliminator.h"
#include "src/storage/BitVector.h"
#include "src/adapters/CarlAdapter.h"
#include "src/utility/constants.h"
#include "src/utility/macros.h"
#include "src/exceptions/InvalidStateException.h"
namespace storm {
namespace solver {
namespace stateelimination {
template<typename SparseModelType>
StateEliminator<SparseModelType>::StateEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions) : transitionMatrix(transitionMatrix), backwardTransitions(backwardTransitions) {
}
template<typename SparseModelType>
void StateEliminator<SparseModelType>::eliminateState(storm::storage::sparse::state_type state, bool removeForwardTransitions, storm::storage::BitVector predecessorConstraint) {
STORM_LOG_TRACE("Eliminating state " << state << ".");
// Start by finding loop probability.
bool hasSelfLoop = false;
ValueType loopProbability = storm::utility::zero<ValueType>();
FlexibleRowType& currentStateSuccessors = transitionMatrix.getRow(state);
for (auto entryIt = currentStateSuccessors.begin(), entryIte = currentStateSuccessors.end(); entryIt != entryIte; ++entryIt) {
if (entryIt->getColumn() >= state) {
if (entryIt->getColumn() == state) {
loopProbability = entryIt->getValue();
hasSelfLoop = true;
// If we do not clear the forward transitions completely, we need to remove the self-loop,
// because we scale all the other outgoing transitions with it anyway.
if (!removeForwardTransitions) {
currentStateSuccessors.erase(entryIt);
}
}
break;
}
}
// Scale all entries in this row with (1 / (1 - loopProbability)) only in case there was a self-loop.
STORM_LOG_TRACE((hasSelfLoop ? "State has self-loop." : "State does not have a self-loop."));
if (hasSelfLoop) {
STORM_LOG_ASSERT(loopProbability != storm::utility::one<ValueType>(), "Must not eliminate state with probability 1 self-loop.");
loopProbability = storm::utility::simplify(storm::utility::one<ValueType>() / (storm::utility::one<ValueType>() - loopProbability));
for (auto& entry : transitionMatrix.getRow(state)) {
// Only scale the non-diagonal entries.
if (entry.getColumn() != state) {
entry.setValue(storm::utility::simplify(entry.getValue() * loopProbability));
}
}
updateValue(state, loopProbability);
}
// Now connect the predecessors of the state being eliminated with its successors.
FlexibleRowType& currentStatePredecessors = backwardTransitions.getRow(state);
// In case we have a constrained elimination, we need to keep track of the new predecessors.
FlexibleRowType newCurrentStatePredecessors;
std::vector<FlexibleRowType> newBackwardProbabilities(currentStateSuccessors.size());
for (auto& backwardProbabilities : newBackwardProbabilities) {
backwardProbabilities.reserve(currentStatePredecessors.size());
}
// Now go through the predecessors and eliminate the ones (satisfying the constraint if given).
for (auto const& predecessorEntry : currentStatePredecessors) {
uint_fast64_t predecessor = predecessorEntry.getColumn();
STORM_LOG_TRACE("Found predecessor " << predecessor << ".");
// Skip the state itself as one of its predecessors.
if (predecessor == state) {
assert(hasSelfLoop);
continue;
}
// Skip the state if the elimination is constrained, but the predecessor is not in the constraint.
if (isFilterPredecessor() && !filterPredecessor(predecessor)) {
newCurrentStatePredecessors.emplace_back(predecessorEntry);
STORM_LOG_TRACE("Not eliminating predecessor " << predecessor << ", because it does not fit the filter.");
continue;
}
STORM_LOG_TRACE("Eliminating predecessor " << predecessor << ".");
// First, find the probability with which the predecessor can move to the current state, because
// the forward probabilities of the state to be eliminated need to be scaled with this factor.
FlexibleRowType& predecessorForwardTransitions = transitionMatrix.getRow(predecessor);
FlexibleRowIterator multiplyElement = std::find_if(predecessorForwardTransitions.begin(), predecessorForwardTransitions.end(), [&](storm::storage::MatrixEntry<typename storm::storage::FlexibleSparseMatrix<ValueType>::index_type, typename storm::storage::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(storm::utility::zero<ValueType>());
// At this point, we need to update the (forward) transitions of the predecessor.
FlexibleRowIterator first1 = predecessorForwardTransitions.begin();
FlexibleRowIterator last1 = predecessorForwardTransitions.end();
FlexibleRowIterator first2 = currentStateSuccessors.begin();
FlexibleRowIterator last2 = currentStateSuccessors.end();
FlexibleRowType newSuccessors;
newSuccessors.reserve((last1 - first1) + (last2 - first2));
std::insert_iterator<FlexibleRowType> result(newSuccessors, newSuccessors.end());
uint_fast64_t successorOffsetInNewBackwardTransitions = 0;
// 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 storm::storage::FlexibleSparseMatrix<ValueType>::index_type, typename storm::storage::FlexibleSparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() != state; } );
break;
}
if (first2->getColumn() < first1->getColumn()) {
auto successorEntry = storm::utility::simplify(std::move(*first2 * multiplyFactor));
*result = successorEntry;
newBackwardProbabilities[successorOffsetInNewBackwardTransitions].emplace_back(predecessor, successorEntry.getValue());
// std::cout << "(1) adding " << first2->getColumn() << " -> " << newBackwardProbabilities[successorOffsetInNewBackwardTransitions].back() << "[" << successorOffsetInNewBackwardTransitions << "]" << std::endl;
++first2;
++successorOffsetInNewBackwardTransitions;
} else if (first1->getColumn() < first2->getColumn()) {
*result = *first1;
++first1;
} else {
auto probability = storm::utility::simplify(first1->getValue() + storm::utility::simplify(multiplyFactor * first2->getValue()));
*result = storm::storage::MatrixEntry<typename storm::storage::FlexibleSparseMatrix<ValueType>::index_type, typename storm::storage::FlexibleSparseMatrix<ValueType>::value_type>(first1->getColumn(), probability);
newBackwardProbabilities[successorOffsetInNewBackwardTransitions].emplace_back(predecessor, probability);
// std::cout << "(2) adding " << first2->getColumn() << " -> " << newBackwardProbabilities[successorOffsetInNewBackwardTransitions].back() << "[" << successorOffsetInNewBackwardTransitions << "]" << std::endl;
++first1;
++first2;
++successorOffsetInNewBackwardTransitions;
}
}
for (; first2 != last2; ++first2) {
if (first2->getColumn() != state) {
auto stateProbability = storm::utility::simplify(std::move(*first2 * multiplyFactor));
*result = stateProbability;
newBackwardProbabilities[successorOffsetInNewBackwardTransitions].emplace_back(predecessor, stateProbability.getValue());
// std::cout << "(3) adding " << first2->getColumn() << " -> " << newBackwardProbabilities[successorOffsetInNewBackwardTransitions].back() << "[" << successorOffsetInNewBackwardTransitions << "]" << std::endl;
++successorOffsetInNewBackwardTransitions;
}
}
// Now move the new transitions in place.
predecessorForwardTransitions = std::move(newSuccessors);
STORM_LOG_TRACE("Fixed new next-state probabilities of predecessor state " << predecessor << ".");
updatePredecessor(predecessor, multiplyFactor, state);
STORM_LOG_TRACE("Updating priority of predecessor.");
updatePriority(predecessor);
}
// Finally, we need to add the predecessor to the set of predecessors of every successor.
uint_fast64_t successorOffsetInNewBackwardTransitions = 0;
for (auto const& successorEntry : currentStateSuccessors) {
if (successorEntry.getColumn() == state) {
continue;
}
FlexibleRowType& successorBackwardTransitions = backwardTransitions.getRow(successorEntry.getColumn());
// std::cout << "old backward trans of " << successorEntry.getColumn() << std::endl;
// for (auto const& trans : successorBackwardTransitions) {
// std::cout << trans << std::endl;
// }
// Delete the current state as a predecessor of the successor state only if we are going to remove the
// current state's forward transitions.
if (removeForwardTransitions) {
FlexibleRowIterator elimIt = std::find_if(successorBackwardTransitions.begin(), successorBackwardTransitions.end(), [&](storm::storage::MatrixEntry<typename storm::storage::FlexibleSparseMatrix<ValueType>::index_type, typename storm::storage::FlexibleSparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() == state; });
STORM_LOG_ASSERT(elimIt != successorBackwardTransitions.end(), "Expected a proper backward transition from " << successorEntry.getColumn() << " to " << state << ", but found none.");
successorBackwardTransitions.erase(elimIt);
}
FlexibleRowIterator first1 = successorBackwardTransitions.begin();
FlexibleRowIterator last1 = successorBackwardTransitions.end();
FlexibleRowIterator first2 = newBackwardProbabilities[successorOffsetInNewBackwardTransitions].begin();
FlexibleRowIterator last2 = newBackwardProbabilities[successorOffsetInNewBackwardTransitions].end();
// std::cout << "adding backward trans " << successorEntry.getColumn() << "[" << successorOffsetInNewBackwardTransitions << "]" << std::endl;
// for (auto const& trans : newBackwardProbabilities[successorOffsetInNewBackwardTransitions]) {
// std::cout << trans << std::endl;
// }
FlexibleRowType newPredecessors;
newPredecessors.reserve((last1 - first1) + (last2 - first2));
std::insert_iterator<FlexibleRowType> result(newPredecessors, newPredecessors.end());
for (; first1 != last1; ++result) {
if (first2 == last2) {
std::copy(first1, last1, result);
break;
}
if (first2->getColumn() < first1->getColumn()) {
if (first2->getColumn() != state) {
*result = *first2;
}
++first2;
} else if (first1->getColumn() == first2->getColumn()) {
if (storm::modelchecker::estimateComplexity(first1->getValue()) > storm::modelchecker::estimateComplexity(first2->getValue())) {
*result = *first1;
} else {
*result = *first2;
}
++first1;
++first2;
} else {
*result = *first1;
++first1;
}
}
if (isFilterPredecessor()) {
std::copy_if(first2, last2, result, [&] (storm::storage::MatrixEntry<typename storm::storage::FlexibleSparseMatrix<ValueType>::index_type, typename storm::storage::FlexibleSparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() != state && filterPredecessor(a.getColumn()); });
} else {
std::copy_if(first2, last2, result, [&] (storm::storage::MatrixEntry<typename storm::storage::FlexibleSparseMatrix<ValueType>::index_type, typename storm::storage::FlexibleSparseMatrix<ValueType>::value_type> const& a) { return a.getColumn() != state; });
}
// Now move the new predecessors in place.
successorBackwardTransitions = std::move(newPredecessors);
// std::cout << "new backward trans of " << successorEntry.getColumn() << std::endl;
// for (auto const& trans : successorBackwardTransitions) {
// std::cout << trans << std::endl;
// }
++successorOffsetInNewBackwardTransitions;
}
STORM_LOG_TRACE("Fixed predecessor lists of successor states.");
if (removeForwardTransitions) {
// Clear the eliminated row to reduce memory consumption.
currentStateSuccessors.clear();
currentStateSuccessors.shrink_to_fit();
}
if (isFilterPredecessor()) {
currentStatePredecessors = std::move(newCurrentStatePredecessors);
} else {
currentStatePredecessors.clear();
currentStatePredecessors.shrink_to_fit();
}
}
template class StateEliminator<storm::models::sparse::Dtmc<double>>;
#ifdef STORM_HAVE_CARL
template class StateEliminator<storm::models::sparse::Dtmc<storm::RationalFunction>>;
#endif
} // namespace stateelimination
} // namespace storage
} // namespace storm

42
src/solver/stateelimination/StateEliminator.h

@ -0,0 +1,42 @@
#ifndef STORM_SOLVER_STATEELIMINATION_STATEELIMINATOR_H_
#define STORM_SOLVER_STATEELIMINATION_STATEELIMINATOR_H_
#include "src/storage/FlexibleSparseMatrix.h"
#include "src/storage/SparseMatrix.h"
#include "src/storage/sparse/StateType.h"
#include "src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h"
namespace storm {
namespace solver {
namespace stateelimination {
template<typename SparseModelType>
class StateEliminator {
typedef typename SparseModelType::ValueType ValueType;
typedef typename storm::storage::FlexibleSparseMatrix<ValueType>::row_type FlexibleRowType;
typedef typename FlexibleRowType::iterator FlexibleRowIterator;
public:
StateEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions);
void eliminateState(storm::storage::sparse::state_type state, bool removeForwardTransitions, storm::storage::BitVector predecessorConstraint = storm::storage::BitVector());
// Virtual methods for base classes to distinguish between different state elimination approaches
virtual void updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability) = 0;
virtual void updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) = 0;
virtual void updatePriority(storm::storage::sparse::state_type const& state) = 0;
virtual bool filterPredecessor(storm::storage::sparse::state_type const& state) = 0;
virtual bool isFilterPredecessor() const = 0;
protected:
storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix;
storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions;
};
} // namespace stateelimination
} // namespace storage
} // namespace storm
#endif // STORM_SOLVER_STATEELIMINATION_STATEELIMINATOR_H_

161
src/storage/FlexibleSparseMatrix.cpp

@ -0,0 +1,161 @@
#include "src/storage/FlexibleSparseMatrix.h"
#include "src/storage/SparseMatrix.h"
#include "src/storage/BitVector.h"
#include "src/adapters/CarlAdapter.h"
#include "src/utility/constants.h"
namespace storm {
namespace storage {
template<typename ValueType>
FlexibleSparseMatrix<ValueType>::FlexibleSparseMatrix(index_type rows) : data(rows), columnCount(0), nonzeroEntryCount(0) {
// Intentionally left empty.
}
template<typename ValueType>
FlexibleSparseMatrix<ValueType>::FlexibleSparseMatrix(storm::storage::SparseMatrix<ValueType> const& matrix, bool setAllValuesToOne) : data(matrix.getRowCount()), columnCount(matrix.getColumnCount()), nonzeroEntryCount(matrix.getNonzeroEntryCount()), nontrivialRowGrouping(matrix.hasNontrivialRowGrouping()) {
if (nontrivialRowGrouping) {
rowGroupIndices = matrix.getRowGroupIndices();
rowIndications = matrix.getRowIndications();
// Not fully implemented yet
assert(false);
}
for (index_type rowIndex = 0; rowIndex < matrix.getRowCount(); ++rowIndex) {
typename storm::storage::SparseMatrix<ValueType>::const_rows row = matrix.getRow(rowIndex);
reserveInRow(rowIndex, row.getNumberOfEntries());
for (auto const& element : row) {
// If the probability is zero, we skip this entry.
if (storm::utility::isZero(element.getValue())) {
continue;
}
if (setAllValuesToOne) {
getRow(rowIndex).emplace_back(element.getColumn(), storm::utility::one<ValueType>());
} else {
getRow(rowIndex).emplace_back(element);
}
}
}
}
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>
typename FlexibleSparseMatrix<ValueType>::row_type const& FlexibleSparseMatrix<ValueType>::getRow(index_type index) const {
return this->data[index];
}
template<typename ValueType>
typename FlexibleSparseMatrix<ValueType>::index_type FlexibleSparseMatrix<ValueType>::getRowCount() const {
return this->data.size();
}
template<typename ValueType>
typename FlexibleSparseMatrix<ValueType>::index_type FlexibleSparseMatrix<ValueType>::getColumnCount() const {
return columnCount;
}
template<typename ValueType>
typename FlexibleSparseMatrix<ValueType>::index_type FlexibleSparseMatrix<ValueType>::getNonzeroEntryCount() const {
return nonzeroEntryCount;
}
template<typename ValueType>
void FlexibleSparseMatrix<ValueType>::updateDimensions() {
this->nonzeroEntryCount = 0;
this->columnCount = 0;
for (auto const& row : this->data) {
for (auto const& element : row) {
assert(!storm::utility::isZero(element.getValue()));
++this->nonzeroEntryCount;
this->columnCount = std::max(element.getColumn() + 1, this->columnCount);
}
}
}
template<typename ValueType>
bool FlexibleSparseMatrix<ValueType>::empty() const {
for (auto const& row : this->data) {
if (!row.empty()) {
return false;
}
}
return true;
}
template<typename ValueType>
bool SparseMatrix<ValueType>::hasNontrivialRowGrouping() const {
return nontrivialRowGrouping;
}
template<typename ValueType>
void FlexibleSparseMatrix<ValueType>::createSubmatrix(storm::storage::BitVector const& rowConstraint, storm::storage::BitVector const& columnConstraint) {
for (uint_fast64_t rowIndex = 0; rowIndex < this->data.size(); ++rowIndex) {
auto& row = this->data[rowIndex];
if (!rowConstraint.get(rowIndex)) {
row.clear();
row.shrink_to_fit();
continue;
}
row_type newRow;
for (auto const& element : row) {
if (columnConstraint.get(element.getColumn())) {
newRow.push_back(element);
}
}
row = std::move(newRow);
}
}
template<typename ValueType>
storm::storage::SparseMatrix<ValueType> FlexibleSparseMatrix<ValueType>::createSparseMatrix() {
storm::storage::SparseMatrixBuilder<ValueType> matrixBuilder(getRowCount(), getColumnCount());
for (uint_fast64_t rowIndex = 0; rowIndex < getRowCount(); ++rowIndex) {
auto& row = this->data[rowIndex];
for (auto const& entry : row) {
matrixBuilder.addNextValue(rowIndex, entry.getColumn(), entry.getValue());
}
}
return matrixBuilder.build();
}
template<typename ValueType>
bool FlexibleSparseMatrix<ValueType>::rowHasDiagonalElement(storm::storage::sparse::state_type state) {
for (auto const& entry : this->getRow(state)) {
if (entry.getColumn() < state) {
continue;
} else if (entry.getColumn() > state) {
return false;
} else if (entry.getColumn() == state) {
return true;
}
}
return false;
}
template<typename ValueType>
std::ostream& operator<<(std::ostream& out, FlexibleSparseMatrix<ValueType> const& matrix) {
for (uint_fast64_t index = 0; index < matrix->data.size(); ++index) {
out << index << " - ";
for (auto const& element : matrix->getRow(index)) {
out << "(" << element.getColumn() << ", " << element.getValue() << ") ";
}
return out;
}
}
// Explicitly instantiate the matrix.
template class FlexibleSparseMatrix<double>;
#ifdef STORM_HAVE_CARL
template class FlexibleSparseMatrix<storm::RationalFunction>;
#endif
} // namespace storage
} // namespace storm

163
src/storage/FlexibleSparseMatrix.h

@ -0,0 +1,163 @@
#ifndef STORM_STORAGE_FLEXIBLESPARSEMATRIX_H_
#define STORM_STORAGE_FLEXIBLESPARSEMATRIX_H_
#include <cstdint>
#include <vector>
#include "src/storage/sparse/StateType.h"
#include "src/storage/SparseMatrix.h"
namespace storm {
namespace storage {
template <typename IndexType, typename ValueType>
class MatrixEntry;
class BitVector;
/*!
* The flexible sparse matrix is used during state elimination.
*/
template<typename ValueType>
class FlexibleSparseMatrix {
public:
// TODO: make this class a bit more consistent with the big sparse matrix and improve it:
// * add output iterator and improve the way the matrix is printed
// * add stuff like clearRow, multiplyRowWithScalar
// * implement row grouping
typedef uint_fast64_t index_type;
typedef ValueType value_type;
typedef std::vector<storm::storage::MatrixEntry<index_type, value_type>> row_type;
typedef typename row_type::iterator iterator;
typedef typename row_type::const_iterator const_iterator;
/*!
* Constructs an empty flexible sparse matrix.
*/
FlexibleSparseMatrix() = default;
/*!
* Constructs a flexible sparse matrix with rows many rows.
* @param rows number of rows.
*/
FlexibleSparseMatrix(index_type rows);
/*!
* Constructs a flexible sparse matrix from a sparse matrix.
* @param matrix Sparse matrix to construct from.
* @param setAllValuesToOne If true, all set entries are set to one. Default is false.
*/
FlexibleSparseMatrix(storm::storage::SparseMatrix<ValueType> const& matrix, bool setAllValuesToOne = false);
/*!
* Reserves space for elements in row.
* @param row Row to reserve in.
* @param numberOfElements Number of elements to reserve space for.
*/
void reserveInRow(index_type row, index_type numberOfElements);
/*!
* Returns an object representing the given row.
*
* @param row The row to get.
* @return An object representing the given row.
*/
row_type& getRow(index_type);
/*!
* Returns an object representing the given row.
*
* @param row The row to get.
* @return An object representing the given row.
*/
row_type const& getRow(index_type) const;
/*!
* Returns the number of rows of the matrix.
*
* @return The number of rows of the matrix.
*/
index_type getRowCount() const;
/*!
* Returns the number of columns of the matrix.
*
* @return The number of columns of the matrix.
*/
index_type getColumnCount() const;
/*!
* Returns the cached number of nonzero entries in the matrix.
*
* @return The number of nonzero entries in the matrix.
*/
index_type getNonzeroEntryCount() const;
/*!
* Recomputes the number of columns and the number of non-zero entries.
*/
void updateDimensions();
/*!
* Checks if the matrix has no elements.
* @return True, if the matrix is empty.
*/
bool empty() const;
/*!
* Retrieves whether the matrix has a (possibly) non-trivial row grouping.
*
* @return True iff the matrix has a (possibly) non-trivial row grouping.
*/
bool hasNontrivialRowGrouping() const;
/*!
* Creates a submatrix of the current matrix in place by dropping all rows and columns whose bits are not
* set to one in the given bit vector.
*
* @param rowConstraint A bit vector indicating which rows to keep.
* @param columnConstraint A bit vector indicating which columns to keep.
*/
void createSubmatrix(storm::storage::BitVector const& rowConstraint, storm::storage::BitVector const& columnConstraint);
/*!
* Creates a sparse matrix from the flexible sparse matrix.
* @return The sparse matrix.
*/
storm::storage::SparseMatrix<ValueType> createSparseMatrix();
/*!
* Checks whether the given state has a self-loop with an arbitrary probability in the probability matrix.
*
* @param state The state for which to check whether it possesses a self-loop.
* @return True iff the given state has a self-loop with an arbitrary probability in the probability matrix.
*/
bool rowHasDiagonalElement(storm::storage::sparse::state_type state);
template<typename TPrime>
friend std::ostream& operator<<(std::ostream& out, FlexibleSparseMatrix<TPrime> const& matrix);
private:
std::vector<row_type> data;
// The number of columns of the matrix.
index_type columnCount;
// The number of entries in the matrix.
index_type nonzeroEntryCount;
// A vector containing the indices at which each given row begins. The values of the entries in row i are
// data[rowIndications[i]] to data[rowIndications[i + 1]] where the last 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 vector indicating the row groups of the matrix.
std::vector<index_type> rowGroupIndices;
};
}
}
#endif /* STORM_STORAGE_FLEXIBLESPARSEMATRIX_H_ */

5
src/storage/SparseMatrix.cpp

@ -452,6 +452,11 @@ namespace storm {
return rowGroupIndices;
}
template<typename ValueType>
std::vector<typename SparseMatrix<ValueType>::index_type> const& SparseMatrix<ValueType>::getRowIndications() const {
return rowIndications;
}
template<typename ValueType>
void SparseMatrix<ValueType>::makeRowsAbsorbing(storm::storage::BitVector const& rows) {
for (auto row : rows) {

7
src/storage/SparseMatrix.h

@ -549,6 +549,13 @@ namespace storm {
*/
std::vector<index_type> const& getRowGroupIndices() const;
/*!
* Returns the indices where new row groups start.
*
* @return The indices where new row groups start.
*/
std::vector<index_type> const& getRowIndications() const;
/*!
* This function makes the given rows absorbing.
*

4
src/storage/expressions/ToRationalFunctionVisitor.cpp

@ -88,12 +88,12 @@ namespace storm {
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IntegerLiteralExpression const& expression) {
return RationalFunctionType(carl::rationalize<storm::RationalNumber>(static_cast<size_t>(expression.getValue())));
return RationalFunctionType(carl::rationalize<storm::CarlRationalNumber>(static_cast<size_t>(expression.getValue())));
}
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(DoubleLiteralExpression const& expression) {
return RationalFunctionType(carl::rationalize<storm::RationalNumber>(expression.getValue()));
return RationalFunctionType(carl::rationalize<storm::CarlRationalNumber>(expression.getValue()));
}
template class ToRationalFunctionVisitor<storm::RationalFunction>;

2
src/utility/vector.h

@ -271,7 +271,7 @@ namespace storm {
* @param target The target vector.
*/
template<class InValueType1, class InValueType2, class OutValueType>
void applyPointwise(std::vector<InValueType1> const& firstOperand, std::vector<InValueType2> const& secondOperand, std::vector<OutValueType>& target, std::function<OutValueType (InValueType1 const&, InValueType2 const&)> function) {
void applyPointwise(std::vector<InValueType1> const& firstOperand, std::vector<InValueType2> const& secondOperand, std::vector<OutValueType>& target, std::function<OutValueType (InValueType1 const&, InValueType2 const&)> const& function) {
#ifdef STORM_HAVE_INTELTBB
tbb::parallel_for(tbb::blocked_range<uint_fast64_t>(0, target.size()),
[&](tbb::blocked_range<uint_fast64_t> const& range) {

Loading…
Cancel
Save