Browse Source

started generalizing elimination to equation system solving

Former-commit-id: aabe89b65f
main
dehnert 9 years ago
parent
commit
40a7948540
  1. 286
      src/solver/stateelimination/EliminatorBase.cpp
  2. 39
      src/solver/stateelimination/EliminatorBase.h
  3. 17
      src/solver/stateelimination/EquationSystemEliminator.cpp
  4. 17
      src/solver/stateelimination/EquationSystemEliminator.h
  5. 242
      src/solver/stateelimination/StateEliminator.cpp
  6. 23
      src/solver/stateelimination/StateEliminator.h

286
src/solver/stateelimination/EliminatorBase.cpp

@ -0,0 +1,286 @@
#include "src/solver/stateelimination/EliminatorBase.h"
#include "src/utility/stateelimination.h"
#include "src/utility/macros.h"
#include "src/utility/constants.h"
#include "src/exceptions/InvalidStateException.h"
namespace storm {
namespace solver {
namespace stateelimination {
using namespace storm::utility::stateelimination;
template<typename ValueType, ScalingMode Mode>
EliminatorBase<ValueType, Mode>::EliminatorBase(storm::storage::FlexibleSparseMatrix<ValueType>& matrix, storm::storage::FlexibleSparseMatrix<ValueType>& transposedMatrix) : matrix(matrix), transposedMatrix(transposedMatrix) {
// Intentionally left empty.
}
template<typename ValueType, ScalingMode Mode>
void EliminatorBase<ValueType, Mode>::eliminate(uint64_t row, uint64_t column, bool clearRow) {
// Start by finding the entry in the given column.
bool hasEntryInColumn = false;
ValueType columnValue = storm::utility::zero<ValueType>();
FlexibleRowType& entriesInRow = matrix.getRow(row);
for (auto entryIt = entriesInRow.begin(), entryIte = entriesInRow.end(); entryIt != entryIte; ++entryIt) {
if (entryIt->getColumn() >= column) {
if (entryIt->getColumn() == column) {
columnValue = entryIt->getValue();
hasEntryInColumn = true;
// If we do not clear the row completely, we need to remove the entry in the requested column.
// All other elements are scaled with the entry anyway.
if (!clearRow) {
entriesInRow.erase(entryIt);
}
}
break;
}
}
// Scale all entries in this row.
// Depending on the scaling mode, we scale the other entries of the row.
STORM_LOG_TRACE((hasEntryInColumn ? "State has entry in column." : "State does not have entry in column."));
if (Mode == ScalingMode::Divide) {
STORM_LOG_ASSERT(hasEntryInColumn, "The scaling mode 'divide' requires an element in the given column.");
STORM_LOG_ASSERT(storm::utility::isZero(columnValue), "The scaling mode 'divide' requires a non-zero element in the given column.");
columnValue = storm::utility::one<ValueType>() / columnValue;
} else if (Mode == ScalingMode::DivideOneMinus) {
if (hasEntryInColumn) {
STORM_LOG_ASSERT(columnValue != storm::utility::one<ValueType>(), "The scaling mode 'divide-one-minus' requires a non-one value in the given column.");
columnValue = storm::utility::simplify(storm::utility::one<ValueType>() / (storm::utility::one<ValueType>() - columnValue));
}
}
if (hasEntryInColumn) {
for (auto entryIt = entriesInRow.begin(), entryIte = entriesInRow.end(); entryIt != entryIte; ++entryIt) {
// Only scale the entries in a different column.
if (entryIt->getColumn() != column) {
entryIt->setValue(storm::utility::simplify(entryIt->getValue() * columnValue));
}
}
updateValue(column, columnValue);
}
// Now substitute the row entries in all other rows that contain an element whose column is the current row.
FlexibleRowType& elementsWithEntryInColumnEqualRow = transposedMatrix.getRow(row);
// In case we have a constrained elimination, we need to keep track of the rows that keep their value
// in the column equal to the current row.
FlexibleRowType rowsKeepingEntryInColumnEqualRow;
// For each entry in the row d, we need to build a list of other rows that will contain an element in the
// column d.
std::vector<FlexibleRowType> newBackwardEntries(entriesInRow.size());
for (auto& backwardEntry : newBackwardEntries) {
backwardEntry.reserve(elementsWithEntryInColumnEqualRow.size());
}
// Now go through the rows with an entry in the column corresponding to the current row and substitute
// the elements of this row unless the elimination is filtered.
for (auto const& predecessorEntry : elementsWithEntryInColumnEqualRow) {
uint_fast64_t predecessor = predecessorEntry.getColumn();
STORM_LOG_TRACE("Found predecessor " << predecessor << ".");
// Skip the row itself.
if (predecessor == row) {
assert(hasEntryInColumn);
continue;
}
// Skip the state if the elimination is constrained, but the predecessor is not in the constraint.
if (isFilterPredecessor() && !filterPredecessor(predecessor)) {
rowsKeepingEntryInColumnEqualRow.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 = matrix.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() == column; });
// 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 = entriesInRow.begin();
FlexibleRowIterator last2 = entriesInRow.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() == column || (first2 != last2 && first2->getColumn() == column)) {
if (first1->getColumn() == column) {
++first1;
}
if (first2 != last2 && first2->getColumn() == column) {
++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() != column; } );
break;
}
if (first2->getColumn() < first1->getColumn()) {
auto successorEntry = storm::utility::simplify(std::move(*first2 * multiplyFactor));
*result = successorEntry;
newBackwardEntries[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 storm::storage::FlexibleSparseMatrix<ValueType>::index_type, typename storm::storage::FlexibleSparseMatrix<ValueType>::value_type>(first1->getColumn(), probability);
newBackwardEntries[successorOffsetInNewBackwardTransitions].emplace_back(predecessor, probability);
++first1;
++first2;
++successorOffsetInNewBackwardTransitions;
}
}
for (; first2 != last2; ++first2) {
if (first2->getColumn() != column) {
auto stateProbability = storm::utility::simplify(std::move(*first2 * multiplyFactor));
*result = stateProbability;
newBackwardEntries[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 << ".");
updatePredecessor(predecessor, multiplyFactor, column);
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 : entriesInRow) {
if (successorEntry.getColumn() == column) {
continue;
}
FlexibleRowType& successorBackwardTransitions = transposedMatrix.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 (clearRow) {
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() == column; });
STORM_LOG_ASSERT(elimIt != successorBackwardTransitions.end(), "Expected a proper backward transition from " << successorEntry.getColumn() << " to " << column << ", but found none.");
successorBackwardTransitions.erase(elimIt);
}
FlexibleRowIterator first1 = successorBackwardTransitions.begin();
FlexibleRowIterator last1 = successorBackwardTransitions.end();
FlexibleRowIterator first2 = newBackwardEntries[successorOffsetInNewBackwardTransitions].begin();
FlexibleRowIterator last2 = newBackwardEntries[successorOffsetInNewBackwardTransitions].end();
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() != column) {
*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 (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() != column && 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() != column; });
}
// Now move the new predecessors in place.
successorBackwardTransitions = std::move(newPredecessors);
++successorOffsetInNewBackwardTransitions;
}
STORM_LOG_TRACE("Fixed predecessor lists of successor states.");
// Clear the row if requested.
if (clearRow) {
entriesInRow.clear();
entriesInRow.shrink_to_fit();
}
// If the substitution was filtered, we need to store the new rows that have an entry in column equal to this row.
if (isFilterPredecessor()) {
elementsWithEntryInColumnEqualRow = std::move(rowsKeepingEntryInColumnEqualRow);
} else {
elementsWithEntryInColumnEqualRow.clear();
elementsWithEntryInColumnEqualRow.shrink_to_fit();
}
}
template<typename ValueType, ScalingMode Mode>
void EliminatorBase<ValueType, Mode>::updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability) {
// Intentionally left empty.
}
template<typename ValueType, ScalingMode Mode>
void EliminatorBase<ValueType, Mode>::updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) {
// Intentionally left empty.
}
template<typename ValueType, ScalingMode Mode>
void EliminatorBase<ValueType, Mode>::updatePriority(storm::storage::sparse::state_type const& state) {
// Intentionally left empty.
}
template<typename ValueType, ScalingMode Mode>
bool EliminatorBase<ValueType, Mode>::filterPredecessor(storm::storage::sparse::state_type const& state) {
STORM_LOG_ASSERT(false, "Must not filter predecessors.");
return false;
}
template<typename ValueType, ScalingMode Mode>
bool EliminatorBase<ValueType, Mode>::isFilterPredecessor() const {
return false;
}
template class EliminatorBase<double, ScalingMode::Divide>;
template class EliminatorBase<storm::RationalNumber, ScalingMode::Divide>;
template class EliminatorBase<storm::RationalFunction, ScalingMode::Divide>;
template class EliminatorBase<double, ScalingMode::DivideOneMinus>;
template class EliminatorBase<storm::RationalNumber, ScalingMode::DivideOneMinus>;
template class EliminatorBase<storm::RationalFunction, ScalingMode::DivideOneMinus>;
}
}
}

39
src/solver/stateelimination/EliminatorBase.h

@ -0,0 +1,39 @@
#pragma once
#include "src/storage/sparse/StateType.h"
#include "src/storage/FlexibleSparseMatrix.h"
namespace storm {
namespace solver {
namespace stateelimination {
enum class ScalingMode {
Divide, DivideOneMinus
};
template<typename ValueType, ScalingMode Mode>
class EliminatorBase {
public:
typedef typename storm::storage::FlexibleSparseMatrix<ValueType>::row_type FlexibleRowType;
typedef typename FlexibleRowType::iterator FlexibleRowIterator;
EliminatorBase(storm::storage::FlexibleSparseMatrix<ValueType>& matrix, storm::storage::FlexibleSparseMatrix<ValueType>& transposedMatrix);
void eliminate(uint64_t row, uint64_t column, bool clearRow);
// Provide virtual methods that can be customized by subclasses to govern side-effect of the elimination.
virtual void updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability);
virtual void updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state);
virtual void updatePriority(storm::storage::sparse::state_type const& state);
virtual bool filterPredecessor(storm::storage::sparse::state_type const& state);
virtual bool isFilterPredecessor() const;
protected:
storm::storage::FlexibleSparseMatrix<ValueType>& matrix;
storm::storage::FlexibleSparseMatrix<ValueType>& transposedMatrix;
};
} // namespace stateelimination
} // namespace storage
} // namespace storm

17
src/solver/stateelimination/EquationSystemEliminator.cpp

@ -0,0 +1,17 @@
#include "src/solver/stateelimination/EquationSystemEliminator.h"
namespace storm {
namespace solver {
namespace stateelimination {
template<typename ValueType>
EquationSystemEliminator<ValueType>::EquationSystemEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& matrix, storm::storage::FlexibleSparseMatrix<ValueType>& transposedMatrix) : EliminatorBase<ValueType, ScalingMode::Divide>(matrix, transposedMatrix) {
// Intentionally left empty.
}
template class EquationSystemEliminator<double>;
template class EquationSystemEliminator<storm::RationalNumber>;
template class EquationSystemEliminator<storm::RationalFunction>;
}
}
}

17
src/solver/stateelimination/EquationSystemEliminator.h

@ -0,0 +1,17 @@
#pragma once
#include "src/solver/stateelimination/EliminatorBase.h"
namespace storm {
namespace solver {
namespace stateelimination {
template<typename ValueType>
class EquationSystemEliminator : public EliminatorBase<ValueType, ScalingMode::Divide> {
public:
EquationSystemEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& matrix, storm::storage::FlexibleSparseMatrix<ValueType>& transposedMatrix);
};
} // namespace stateelimination
} // namespace storage
} // namespace storm

242
src/solver/stateelimination/StateEliminator.cpp

@ -17,250 +17,14 @@ namespace storm {
using namespace storm::utility::stateelimination;
template<typename ValueType>
StateEliminator<ValueType>::StateEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions) : transitionMatrix(transitionMatrix), backwardTransitions(backwardTransitions) {
StateEliminator<ValueType>::StateEliminator(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions) : EliminatorBase<ValueType, ScalingMode::DivideOneMinus>(transitionMatrix, backwardTransitions) {
// Intentionally left empty.
}
template<typename ValueType>
void StateEliminator<ValueType>::eliminateState(storm::storage::sparse::state_type state, bool removeForwardTransitions, storm::storage::BitVector predecessorConstraint) {
void StateEliminator<ValueType>::eliminateState(storm::storage::sparse::state_type state, bool removeForwardTransitions) {
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());
++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);
++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 << ".");
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());
// 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();
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 (estimateComplexity(first1->getValue()) > 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);
++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<typename ValueType>
void StateEliminator<ValueType>::updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability) {
// Intentionally left empty.
}
template<typename ValueType>
void StateEliminator<ValueType>::updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) {
// Intentionally left empty.
}
template<typename ValueType>
void StateEliminator<ValueType>::updatePriority(storm::storage::sparse::state_type const& state) {
// Intentionally left empty.
}
template<typename ValueType>
bool StateEliminator<ValueType>::filterPredecessor(storm::storage::sparse::state_type const& state) {
STORM_LOG_ASSERT(false, "Must not filter predecessors.");
return false;
}
template<typename ValueType>
bool StateEliminator<ValueType>::isFilterPredecessor() const {
return false;
this->eliminate(state, state, removeForwardTransitions);
}
template class StateEliminator<double>;

23
src/solver/stateelimination/StateEliminator.h

@ -1,35 +1,18 @@
#ifndef STORM_SOLVER_STATEELIMINATION_STATEELIMINATOR_H_
#define STORM_SOLVER_STATEELIMINATION_STATEELIMINATOR_H_
#include "src/storage/sparse/StateType.h"
#include "src/storage/FlexibleSparseMatrix.h"
#include "src/storage/BitVector.h"
#include "src/solver/stateelimination/EliminatorBase.h"
namespace storm {
namespace solver {
namespace stateelimination {
template<typename ValueType>
class StateEliminator {
class StateEliminator : public EliminatorBase<ValueType, ScalingMode::DivideOneMinus> {
public:
typedef typename storm::storage::FlexibleSparseMatrix<ValueType>::row_type FlexibleRowType;
typedef typename FlexibleRowType::iterator FlexibleRowIterator;
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());
// Provide virtual methods that can be customized by subclasses to govern side-effect of the elimination.
virtual void updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability);
virtual void updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state);
virtual void updatePriority(storm::storage::sparse::state_type const& state);
virtual bool filterPredecessor(storm::storage::sparse::state_type const& state);
virtual bool isFilterPredecessor() const;
protected:
storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix;
storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions;
void eliminateState(storm::storage::sparse::state_type state, bool removeForwardTransitions);
};
} // namespace stateelimination

|||||||
100:0
Loading…
Cancel
Save