|
|
@ -1,4 +1,5 @@ |
|
|
|
#include <queue>
|
|
|
|
#include <storm/generator/StateBehavior.h>
|
|
|
|
|
|
|
|
#include "storm/models/sparse/MarkovAutomaton.h"
|
|
|
|
|
|
|
@ -270,6 +271,9 @@ namespace storm { |
|
|
|
template<typename ValueType, typename RewardModelType> |
|
|
|
std::shared_ptr<MarkovAutomaton<ValueType, RewardModelType>> |
|
|
|
MarkovAutomaton<ValueType, RewardModelType>::eliminateNonmarkovianStates() const { |
|
|
|
// TODO reward models
|
|
|
|
|
|
|
|
STORM_LOG_WARN("State elimination is currently not label preserving!"); |
|
|
|
if (isClosed() && markovianStates.full()) { |
|
|
|
storm::storage::sparse::ModelComponents<ValueType, RewardModelType> components( |
|
|
|
this->getTransitionMatrix(), this->getStateLabeling(), this->getRewardModels(), false); |
|
|
@ -356,10 +360,10 @@ namespace storm { |
|
|
|
|
|
|
|
// At this point, we hopefully have a valid mapping which eliminates a lot of states
|
|
|
|
|
|
|
|
STORM_PRINT("Elimination Mapping" << std::endl) |
|
|
|
/*STORM_PRINT("Elimination Mapping" << std::endl)
|
|
|
|
for (auto entry : eliminationMapping) { |
|
|
|
STORM_PRINT(std::to_string(entry.first) << " -> " << std::to_string(entry.second) << std::endl) |
|
|
|
} |
|
|
|
}*/ |
|
|
|
STORM_PRINT("Eliminating " << eliminationMapping.size() << " states" << std::endl) |
|
|
|
|
|
|
|
// TODO explore if one can construct elimination mapping and state remapping in one step
|
|
|
@ -369,31 +373,95 @@ namespace storm { |
|
|
|
uint_fast64_t currentNewState = 0; |
|
|
|
for (uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) { |
|
|
|
if (eliminationMapping.count(state) > 0) { |
|
|
|
STORM_PRINT("Eliminate state " << state << std::endl) |
|
|
|
if (stateRemapping[eliminationMapping[state]] == uint_fast64_t(-1)) { |
|
|
|
STORM_PRINT( |
|
|
|
"State " << eliminationMapping[state] << " is not mapped yet! Current New State: " |
|
|
|
<< currentNewState << std::endl) |
|
|
|
|
|
|
|
stateRemapping[eliminationMapping[state]] = currentNewState; |
|
|
|
stateRemapping[state] = currentNewState; |
|
|
|
++currentNewState; |
|
|
|
queue.push(eliminationMapping[state]); |
|
|
|
} else { |
|
|
|
stateRemapping[state] = stateRemapping[eliminationMapping[state]]; |
|
|
|
} |
|
|
|
} else if (stateRemapping[state] == uint_fast64_t(-1)) { |
|
|
|
stateRemapping[state] = currentNewState; |
|
|
|
queue.push(state); |
|
|
|
++currentNewState; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (uint_fast64_t state = 0; state < stateRemapping.size(); ++state) STORM_PRINT( |
|
|
|
state << "->" << stateRemapping[state] << std::endl) |
|
|
|
// Build the new MA
|
|
|
|
storm::storage::SparseMatrix<ValueType> newTransitionMatrix; |
|
|
|
storm::models::sparse::StateLabeling newStateLabeling( |
|
|
|
this->getNumberOfStates() - eliminationMapping.size()); |
|
|
|
storm::storage::BitVector newMarkovianStates(this->getNumberOfStates() - eliminationMapping.size(), |
|
|
|
false); |
|
|
|
std::vector<ValueType> newExitRates; |
|
|
|
//TODO choice labeling
|
|
|
|
boost::optional <storm::models::sparse::ChoiceLabeling> choiceLabeling; |
|
|
|
|
|
|
|
// Initialize the matrix builder and helper variables
|
|
|
|
storm::storage::SparseMatrixBuilder<ValueType> matrixBuilder = storm::storage::SparseMatrixBuilder<ValueType>( |
|
|
|
0, 0, 0, false, true, 0); |
|
|
|
uint_fast64_t currentRow = 0; |
|
|
|
uint_fast64_t state = 0; |
|
|
|
while (!queue.empty()) { |
|
|
|
state = queue.front(); |
|
|
|
queue.pop(); |
|
|
|
|
|
|
|
for (auto const &label : this->getLabelsOfState(state)) { |
|
|
|
if (!newStateLabeling.containsLabel(label)) { |
|
|
|
newStateLabeling.addLabel(label); |
|
|
|
} |
|
|
|
|
|
|
|
newStateLabeling.addLabelToState(label, stateRemapping[state]); |
|
|
|
} |
|
|
|
|
|
|
|
// Use a set to not include redundant rows
|
|
|
|
std::set<std::map<uint_fast64_t, ValueType>> rowSet; |
|
|
|
for (uint_fast64_t row = 0; row < this->getTransitionMatrix().getRowGroupSize(state); ++row) { |
|
|
|
std::map<uint_fast64_t, ValueType> transitions; |
|
|
|
for (typename storm::storage::SparseMatrix<ValueType>::const_iterator itEntry = this->getTransitionMatrix().getRow( |
|
|
|
state, row).begin(); |
|
|
|
itEntry != this->getTransitionMatrix().getRow(state, row).end(); ++itEntry) { |
|
|
|
uint_fast64_t newId = stateRemapping[itEntry->getColumn()]; |
|
|
|
if (transitions.count(newId) == 0) { |
|
|
|
transitions[newId] = itEntry->getValue(); |
|
|
|
} else { |
|
|
|
transitions[newId] += itEntry->getValue(); |
|
|
|
} |
|
|
|
} |
|
|
|
rowSet.insert(transitions); |
|
|
|
} |
|
|
|
|
|
|
|
// correctly set rates
|
|
|
|
auto rate = storm::utility::zero<ValueType>(); |
|
|
|
|
|
|
|
if (this->isMarkovianState(state)) { |
|
|
|
newMarkovianStates.set(stateRemapping[state], true); |
|
|
|
rate = this->exitRates.at(state); |
|
|
|
} |
|
|
|
|
|
|
|
newExitRates.push_back(rate); |
|
|
|
// Build matrix
|
|
|
|
matrixBuilder.newRowGroup(currentRow); |
|
|
|
for (auto const &row : rowSet) { |
|
|
|
for (auto const &transition : row) { |
|
|
|
matrixBuilder.addNextValue(currentRow, transition.first, transition.second); |
|
|
|
//STORM_PRINT(stateRemapping[state] << "->" << transition.first << " : " << transition.second << std::endl)
|
|
|
|
} |
|
|
|
++currentRow; |
|
|
|
} |
|
|
|
} |
|
|
|
newTransitionMatrix = matrixBuilder.build(); |
|
|
|
|
|
|
|
// Build the new matrix
|
|
|
|
storm::storage::sparse::ModelComponents<ValueType, RewardModelType> newComponents = storm::storage::sparse::ModelComponents<ValueType, RewardModelType>( |
|
|
|
std::move(newTransitionMatrix), std::move(newStateLabeling)); |
|
|
|
|
|
|
|
newComponents.rateTransitions = false; |
|
|
|
newComponents.markovianStates = std::move(newMarkovianStates); |
|
|
|
newComponents.exitRates = std::move(newExitRates); |
|
|
|
|
|
|
|
return nullptr; |
|
|
|
return std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType>>( |
|
|
|
std::move(newComponents)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|