You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
326 lines
19 KiB
326 lines
19 KiB
#include "storm/modelchecker/prctl/helper/SparseMdpEndComponentInformation.h"
|
|
|
|
#include "storm/storage/BitVector.h"
|
|
#include "storm/storage/MaximalEndComponentDecomposition.h"
|
|
|
|
#include "storm/adapters/RationalNumberAdapter.h"
|
|
#include "storm/adapters/RationalFunctionAdapter.h"
|
|
|
|
namespace storm {
|
|
namespace modelchecker {
|
|
namespace helper {
|
|
|
|
template<typename ValueType>
|
|
SparseMdpEndComponentInformation<ValueType>::SparseMdpEndComponentInformation(storm::storage::MaximalEndComponentDecomposition<ValueType> const& endComponentDecomposition, storm::storage::BitVector const& maybeStates) : NOT_IN_EC(std::numeric_limits<uint64_t>::max()), eliminatedEndComponents(false), numberOfMaybeStatesInEc(0), numberOfMaybeStatesNotInEc(0), numberOfEc(endComponentDecomposition.size()) {
|
|
|
|
// (1) Compute how many maybe states there are before each other maybe state.
|
|
maybeStatesBefore = maybeStates.getNumberOfSetBitsBeforeIndices();
|
|
|
|
// (2) Create mapping from maybe states to their MEC. If they are not contained in an MEC, their value
|
|
// is set to a special constant.
|
|
maybeStateToEc.resize(maybeStates.getNumberOfSetBits(), NOT_IN_EC);
|
|
uint64_t mecIndex = 0;
|
|
for (auto const& mec : endComponentDecomposition) {
|
|
for (auto const& stateActions : mec) {
|
|
maybeStateToEc[maybeStatesBefore[stateActions.first]] = mecIndex;
|
|
++numberOfMaybeStatesInEc;
|
|
}
|
|
++mecIndex;
|
|
}
|
|
|
|
// (3) Compute number of states not in MECs.
|
|
numberOfMaybeStatesNotInEc = maybeStateToEc.size() - numberOfMaybeStatesInEc;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
bool SparseMdpEndComponentInformation<ValueType>::isMaybeStateInEc(uint64_t maybeState) const {
|
|
return maybeStateToEc[maybeState] != NOT_IN_EC;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
bool SparseMdpEndComponentInformation<ValueType>::isStateInEc(uint64_t state) const {
|
|
return maybeStateToEc[maybeStatesBefore[state]] != NOT_IN_EC;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
std::vector<uint64_t> SparseMdpEndComponentInformation<ValueType>::getNumberOfMaybeStatesNotInEcBeforeIndices() const {
|
|
std::vector<uint64_t> result(maybeStateToEc.size());
|
|
|
|
uint64_t count = 0;
|
|
auto resultIt = result.begin();
|
|
for (auto const& e : maybeStateToEc) {
|
|
*resultIt = count;
|
|
if (e != NOT_IN_EC) {
|
|
++count;
|
|
}
|
|
++resultIt;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
uint64_t SparseMdpEndComponentInformation<ValueType>::getNumberOfMaybeStatesNotInEc() const {
|
|
return numberOfMaybeStatesNotInEc;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
uint64_t SparseMdpEndComponentInformation<ValueType>::getEc(uint64_t state) const {
|
|
return maybeStateToEc[maybeStatesBefore[state]];
|
|
}
|
|
|
|
template<typename ValueType>
|
|
uint64_t SparseMdpEndComponentInformation<ValueType>::getRowGroupAfterElimination(uint64_t state) const {
|
|
return numberOfMaybeStatesNotInEc + getEc(state);
|
|
}
|
|
|
|
template<typename ValueType>
|
|
bool SparseMdpEndComponentInformation<ValueType>::getEliminatedEndComponents() const {
|
|
return eliminatedEndComponents;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
uint64_t SparseMdpEndComponentInformation<ValueType>::getNotInEcMarker() const {
|
|
return NOT_IN_EC;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
SparseMdpEndComponentInformation<ValueType> SparseMdpEndComponentInformation<ValueType>::eliminateEndComponents(storm::storage::MaximalEndComponentDecomposition<ValueType> const& endComponentDecomposition, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const* sumColumns, storm::storage::BitVector const* selectedChoices, std::vector<ValueType> const* summand, storm::storage::SparseMatrix<ValueType>& submatrix, std::vector<ValueType>* columnSumVector, std::vector<ValueType>* summandResultVector) {
|
|
|
|
SparseMdpEndComponentInformation<ValueType> result(endComponentDecomposition, maybeStates);
|
|
|
|
// (1) Compute the number of maybe states not in ECs before any other maybe state.
|
|
std::vector<uint64_t> maybeStatesNotInEcBefore = result.getNumberOfMaybeStatesNotInEcBeforeIndices();
|
|
uint64_t numberOfStates = result.numberOfMaybeStatesNotInEc + result.numberOfEc;
|
|
|
|
STORM_LOG_TRACE("Found " << numberOfStates << " states, " << result.numberOfMaybeStatesNotInEc << " not in ECs, " << result.numberOfMaybeStatesInEc << " in ECs and " << result.numberOfEc << " ECs.");
|
|
|
|
// Prepare builder and vector storage.
|
|
storm::storage::SparseMatrixBuilder<ValueType> builder(0, numberOfStates, 0, true, true, numberOfStates);
|
|
STORM_LOG_ASSERT((sumColumns && columnSumVector) || (!sumColumns && !columnSumVector), "Expecting a bit vector for which columns to sum iff there is a column sum result vector.");
|
|
if (columnSumVector) {
|
|
columnSumVector->resize(numberOfStates);
|
|
}
|
|
STORM_LOG_ASSERT((summand && summandResultVector) || (!summand && !summandResultVector), "Expecting summand iff there is a summand result vector.");
|
|
if (summandResultVector) {
|
|
summandResultVector->resize(numberOfStates);
|
|
}
|
|
std::vector<std::pair<uint64_t, ValueType>> ecValuePairs;
|
|
|
|
// (2) Create the parts of the submatrix and vector b that belong to states not contained in ECs.
|
|
uint64_t currentRow = 0;
|
|
for (auto state : maybeStates) {
|
|
if (!result.isStateInEc(state)) {
|
|
builder.newRowGroup(currentRow);
|
|
for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
|
|
// If the choices is not in the selected ones, drop it.
|
|
if (selectedChoices && !selectedChoices->get(row)) {
|
|
continue;
|
|
}
|
|
|
|
ecValuePairs.clear();
|
|
|
|
if (summand) {
|
|
(*summandResultVector)[currentRow] += (*summand)[row];
|
|
}
|
|
for (auto const& e : transitionMatrix.getRow(row)) {
|
|
if (sumColumns && sumColumns->get(e.getColumn())) {
|
|
(*columnSumVector)[currentRow] += e.getValue();
|
|
} else if (maybeStates.get(e.getColumn())) {
|
|
// If the target state of the transition is not contained in an EC, we can just add the entry.
|
|
if (result.isStateInEc(e.getColumn())) {
|
|
builder.addNextValue(currentRow, maybeStatesNotInEcBefore[result.maybeStatesBefore[e.getColumn()]], e.getValue());
|
|
} else {
|
|
// Otherwise, we store the information that the state can go to a certain EC.
|
|
ecValuePairs.emplace_back(result.getEc(e.getColumn()), e.getValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ecValuePairs.empty()) {
|
|
std::sort(ecValuePairs.begin(), ecValuePairs.end());
|
|
|
|
for (auto const& e : ecValuePairs) {
|
|
builder.addNextValue(currentRow, result.numberOfMaybeStatesNotInEc + e.first, e.second);
|
|
}
|
|
}
|
|
|
|
++currentRow;
|
|
}
|
|
}
|
|
}
|
|
|
|
// (3) Create the parts of the submatrix and vector b that belong to states contained in ECs.
|
|
for (auto const& mec : endComponentDecomposition) {
|
|
builder.newRowGroup(currentRow);
|
|
|
|
for (auto const& stateActions : mec) {
|
|
uint64_t const& state = stateActions.first;
|
|
for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
|
|
// If the choice is contained in the MEC, drop it.
|
|
if (stateActions.second.find(row) != stateActions.second.end()) {
|
|
continue;
|
|
}
|
|
|
|
// If the choices is not in the selected ones, drop it.
|
|
if (selectedChoices && !selectedChoices->get(row)) {
|
|
continue;
|
|
}
|
|
|
|
ecValuePairs.clear();
|
|
|
|
if (summand) {
|
|
(*summandResultVector)[currentRow] += (*summand)[row];
|
|
}
|
|
for (auto const& e : transitionMatrix.getRow(row)) {
|
|
if (sumColumns && sumColumns->get(e.getColumn())) {
|
|
(*columnSumVector)[currentRow] += e.getValue();
|
|
} else if (maybeStates.get(e.getColumn())) {
|
|
// If the target state of the transition is not contained in an EC, we can just add the entry.
|
|
if (result.isStateInEc(e.getColumn())) {
|
|
builder.addNextValue(currentRow, maybeStatesNotInEcBefore[result.maybeStatesBefore[e.getColumn()]], e.getValue());
|
|
} else {
|
|
// Otherwise, we store the information that the state can go to a certain EC.
|
|
ecValuePairs.emplace_back(result.getEc(e.getColumn()), e.getValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ecValuePairs.empty()) {
|
|
std::sort(ecValuePairs.begin(), ecValuePairs.end());
|
|
|
|
for (auto const& e : ecValuePairs) {
|
|
builder.addNextValue(currentRow, result.getNumberOfMaybeStatesNotInEc() + e.first, e.second);
|
|
}
|
|
}
|
|
|
|
++currentRow;
|
|
}
|
|
}
|
|
}
|
|
|
|
submatrix = builder.build(currentRow);
|
|
return result;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
SparseMdpEndComponentInformation<ValueType> SparseMdpEndComponentInformation<ValueType>::eliminateEndComponents(storm::storage::MaximalEndComponentDecomposition<ValueType> const& endComponentDecomposition, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType>& rhsVector, storm::storage::BitVector const& maybeStates, storm::storage::SparseMatrix<ValueType>& submatrix, std::vector<ValueType>& subvector) {
|
|
|
|
SparseMdpEndComponentInformation<ValueType> result(endComponentDecomposition, maybeStates);
|
|
|
|
// (1) Compute the number of maybe states not in ECs before any other maybe state.
|
|
std::vector<uint64_t> maybeStatesNotInEcBefore = result.getNumberOfMaybeStatesNotInEcBeforeIndices();
|
|
uint64_t numberOfStates = result.numberOfMaybeStatesNotInEc + result.numberOfEc;
|
|
|
|
STORM_LOG_TRACE("Found " << numberOfStates << " states, " << result.numberOfMaybeStatesNotInEc << " not in ECs, " << result.numberOfMaybeStatesInEc << " in ECs and " << result.numberOfEc << " ECs.");
|
|
|
|
// Prepare builder and vector storage.
|
|
storm::storage::SparseMatrixBuilder<ValueType> builder(0, numberOfStates, 0, true, true, numberOfStates);
|
|
subvector.resize(numberOfStates);
|
|
|
|
std::vector<std::pair<uint64_t, ValueType>> ecValuePairs;
|
|
|
|
// (2) Create the parts of the submatrix and vector b that belong to states not contained in ECs.
|
|
uint64_t currentRow = 0;
|
|
for (auto state : maybeStates) {
|
|
if (!result.isStateInEc(state)) {
|
|
builder.newRowGroup(currentRow);
|
|
for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
|
|
// Copy over the entry of the vector.
|
|
subvector[currentRow] = rhsVector[row];
|
|
|
|
ecValuePairs.clear();
|
|
for (auto const& e : transitionMatrix.getRow(row)) {
|
|
if (maybeStates.get(e.getColumn())) {
|
|
// If the target state of the transition is not contained in an EC, we can just add the entry.
|
|
if (result.isStateInEc(e.getColumn())) {
|
|
builder.addNextValue(currentRow, maybeStatesNotInEcBefore[result.maybeStatesBefore[e.getColumn()]], e.getValue());
|
|
} else {
|
|
// Otherwise, we store the information that the state can go to a certain EC.
|
|
ecValuePairs.emplace_back(result.getEc(e.getColumn()), e.getValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ecValuePairs.empty()) {
|
|
std::sort(ecValuePairs.begin(), ecValuePairs.end());
|
|
|
|
for (auto const& e : ecValuePairs) {
|
|
builder.addNextValue(currentRow, result.numberOfMaybeStatesNotInEc + e.first, e.second);
|
|
}
|
|
}
|
|
|
|
++currentRow;
|
|
}
|
|
}
|
|
}
|
|
|
|
// (3) Create the parts of the submatrix and vector b that belong to states contained in ECs.
|
|
for (auto const& mec : endComponentDecomposition) {
|
|
builder.newRowGroup(currentRow);
|
|
|
|
for (auto const& stateActions : mec) {
|
|
uint64_t const& state = stateActions.first;
|
|
for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
|
|
// If the choice is contained in the MEC, drop it.
|
|
if (stateActions.second.find(row) != stateActions.second.end()) {
|
|
continue;
|
|
}
|
|
|
|
// Copy over the entry of the vector.
|
|
subvector[currentRow] = rhsVector[row];
|
|
|
|
ecValuePairs.clear();
|
|
for (auto const& e : transitionMatrix.getRow(row)) {
|
|
if (maybeStates.get(e.getColumn())) {
|
|
// If the target state of the transition is not contained in an EC, we can just add the entry.
|
|
if (result.isStateInEc(e.getColumn())) {
|
|
builder.addNextValue(currentRow, maybeStatesNotInEcBefore[result.maybeStatesBefore[e.getColumn()]], e.getValue());
|
|
} else {
|
|
// Otherwise, we store the information that the state can go to a certain EC.
|
|
ecValuePairs.emplace_back(result.getEc(e.getColumn()), e.getValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ecValuePairs.empty()) {
|
|
std::sort(ecValuePairs.begin(), ecValuePairs.end());
|
|
|
|
for (auto const& e : ecValuePairs) {
|
|
builder.addNextValue(currentRow, result.getNumberOfMaybeStatesNotInEc() + e.first, e.second);
|
|
}
|
|
}
|
|
|
|
++currentRow;
|
|
}
|
|
}
|
|
}
|
|
|
|
submatrix = builder.build();
|
|
return result;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
void SparseMdpEndComponentInformation<ValueType>::setValues(std::vector<ValueType>& result, storm::storage::BitVector const& maybeStates, std::vector<ValueType> const& fromResult) {
|
|
auto notInEcResultIt = result.begin();
|
|
for (auto state : maybeStates) {
|
|
if (this->isStateInEc(state)) {
|
|
result[state] = result[this->getRowGroupAfterElimination(state)];
|
|
} else {
|
|
result[state] = *notInEcResultIt;
|
|
++notInEcResultIt;
|
|
}
|
|
}
|
|
STORM_LOG_ASSERT(notInEcResultIt == result.begin() + this->getNumberOfMaybeStatesNotInEc(), "Mismatching iterators.");
|
|
}
|
|
|
|
template class SparseMdpEndComponentInformation<double>;
|
|
|
|
#ifdef STORM_HAVE_CARL
|
|
template class SparseMdpEndComponentInformation<storm::RationalNumber>;
|
|
template class SparseMdpEndComponentInformation<storm::RationalFunction>;
|
|
#endif
|
|
|
|
}
|
|
}
|
|
}
|