11 changed files with 442 additions and 168 deletions
-
4src/storm/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp
-
10src/storm/modelchecker/region/ApproximationModel.cpp
-
4src/storm/modelchecker/region/SamplingModel.cpp
-
32src/storm/models/sparse/StandardRewardModel.cpp
-
9src/storm/models/sparse/StandardRewardModel.h
-
91src/storm/storage/FlexibleSparseMatrix.cpp
-
22src/storm/storage/FlexibleSparseMatrix.h
-
190src/storm/transformer/GoalStateMerger.cpp
-
149src/storm/transformer/GoalStateMerger.h
-
77src/storm/transformer/SparseParametricDtmcSimplifier.cpp
-
6src/storm/transformer/SparseParametricModelSimplifier.cpp
@ -0,0 +1,190 @@ |
|||||
|
#include "storm/transformer/GoalStateMerger.h"
|
||||
|
|
||||
|
#include <limits>
|
||||
|
#include <memory>
|
||||
|
|
||||
|
#include "storm/utility/constants.h"
|
||||
|
#include "storm/utility/macros.h"
|
||||
|
#include "storm/utility/vector.h"
|
||||
|
#include "storm/models/sparse/Dtmc.h"
|
||||
|
#include "storm/models/sparse/Mdp.h"
|
||||
|
#include "storm/models/sparse/StandardRewardModel.h"
|
||||
|
|
||||
|
#include "storm/exceptions/InvalidArgumentException.h"
|
||||
|
|
||||
|
|
||||
|
namespace storm { |
||||
|
namespace transformer { |
||||
|
|
||||
|
template <typename SparseModelType> |
||||
|
GoalStateMerger<SparseModelType>::GoalStateMerger(SparseModelType const& model) : originalModel(model) { |
||||
|
// Intentionally left empty
|
||||
|
} |
||||
|
|
||||
|
template <typename SparseModelType> |
||||
|
std::shared_ptr<SparseModelType> GoalStateMerger<SparseModelType>::mergeTargetAndSinkStates(storm::storage::BitVector const& maybeStates, storm::storage::BitVector& targetStates, storm::storage::BitVector& sinkStates, std::vector<std::string> const& selectedRewardModels) { |
||||
|
STORM_LOG_THROW(maybeStates.isDisjointFrom(targetStates) && targetStates.isDisjointFrom(sinkStates) && sinkStates.isDisjointFrom(maybeStates), storm::exceptions::InvalidArgumentException, "maybestates, targetstates, and sinkstates are assumed to be disjoint when creating the submodel. However, this is not the case."); |
||||
|
|
||||
|
boost::optional<uint_fast64_t> targetState, sinkState; |
||||
|
auto builder = initializeTransitionMatrixBuilder(maybeStates, targetStates, sinkStates, targetState, sinkState); |
||||
|
auto transitionMatrix = buildTransitionMatrix(maybeStates, targetStates, sinkStates, targetState, sinkState, builder); |
||||
|
|
||||
|
uint_fast64_t resNumStates = transitionMatrix.getRowGroupCount(); |
||||
|
|
||||
|
// Get the labeling for the initial states
|
||||
|
storm::storage::BitVector initialStates = originalModel.getInitialStates() % maybeStates; |
||||
|
initialStates.resize(resNumStates, false); |
||||
|
if(!originalModel.getInitialStates().isDisjointFrom(targetStates)) { |
||||
|
initialStates.set(*targetState, true); |
||||
|
} |
||||
|
if(!originalModel.getInitialStates().isDisjointFrom(sinkStates)) { |
||||
|
initialStates.set(*sinkState, true); |
||||
|
} |
||||
|
storm::models::sparse::StateLabeling labeling(resNumStates); |
||||
|
labeling.addLabel("init", std::move(initialStates)); |
||||
|
|
||||
|
// Get the reward models
|
||||
|
std::unordered_map<std::string, typename SparseModelType::RewardModelType> rewardModels; |
||||
|
for (auto rewardModelName : selectedRewardModels) { |
||||
|
auto origTotalRewards = originalModel.getRewardModel(rewardModelName).getTotalRewardVector(originalModel.getTransitionMatrix()); |
||||
|
auto resTotalRewards = storm::utility::vector::filterVector(origTotalRewards, maybeStates); |
||||
|
resTotalRewards.resize(resNumStates, storm::utility::zero<typename SparseModelType::RewardModelType::ValueType>()); |
||||
|
rewardModels.insert(std::make_pair(rewardModelName, typename SparseModelType::RewardModelType(boost::none, resTotalRewards))); |
||||
|
} |
||||
|
|
||||
|
// modify the given target and sink states
|
||||
|
targetStates = storm::storage::BitVector(resNumStates, false); |
||||
|
if(targetState) { |
||||
|
targetStates.set(*targetState, true); |
||||
|
} |
||||
|
sinkStates = storm::storage::BitVector(resNumStates, false); |
||||
|
if(sinkState) { |
||||
|
sinkStates.set(*sinkState, true); |
||||
|
} |
||||
|
|
||||
|
// Return the result
|
||||
|
return std::make_shared<SparseModelType>(std::move(transitionMatrix), std::move(labeling), std::move(rewardModels)); |
||||
|
} |
||||
|
|
||||
|
template <typename SparseModelType> |
||||
|
storm::storage::SparseMatrixBuilder<typename SparseModelType::ValueType> GoalStateMerger<SparseModelType>::initializeTransitionMatrixBuilder(storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& sinkStates, boost::optional<uint_fast64_t>& newTargetState, boost::optional<uint_fast64_t>& newSinkState) { |
||||
|
|
||||
|
storm::storage::SparseMatrix<typename SparseModelType::ValueType> const& origMatrix = originalModel.getTransitionMatrix(); |
||||
|
|
||||
|
// Get the number of rows, cols and entries that the resulting transition matrix will have.
|
||||
|
uint_fast64_t resNumStates(maybeStates.getNumberOfSetBits()), resNumActions(0), resNumTransitions(0); |
||||
|
bool targetStateRequired = !originalModel.getInitialStates().isDisjointFrom(targetStates); |
||||
|
bool sinkStateRequired = !originalModel.getInitialStates().isDisjointFrom(targetStates); |
||||
|
for( auto state : maybeStates) { |
||||
|
resNumActions += origMatrix.getRowGroupSize(state); |
||||
|
bool hasTransitionToTarget(false), hasTransitionToSink(false); |
||||
|
auto const& endOfRowGroup = origMatrix.getRowGroupIndices()[state+1]; |
||||
|
for (uint_fast64_t row = origMatrix.getRowGroupIndices()[state]; row < endOfRowGroup; ++row) { |
||||
|
for (auto const& entry : origMatrix.getRow(row)) { |
||||
|
if(maybeStates.get(entry.getColumn())) { |
||||
|
++resNumTransitions; |
||||
|
} else if (targetStates.get(entry.getColumn())) { |
||||
|
hasTransitionToTarget = true; |
||||
|
} else if (sinkStates.get(entry.getColumn())) { |
||||
|
hasTransitionToSink = true; |
||||
|
} else { |
||||
|
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "There is a transition originating from a maybestate that does not lead to a maybe-, target-, or sinkstate."); |
||||
|
} |
||||
|
} |
||||
|
if(hasTransitionToTarget) { |
||||
|
++resNumTransitions; |
||||
|
targetStateRequired = true; |
||||
|
} |
||||
|
if(hasTransitionToSink) { |
||||
|
++resNumTransitions; |
||||
|
sinkStateRequired = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Get the index of the target/ sink state in the resulting model (if these states will exist)
|
||||
|
if(targetStateRequired) { |
||||
|
newTargetState = resNumStates; |
||||
|
++resNumStates; |
||||
|
++resNumActions; |
||||
|
++resNumTransitions; |
||||
|
} |
||||
|
if(sinkStateRequired) { |
||||
|
newSinkState = resNumStates; |
||||
|
++resNumStates; |
||||
|
++resNumActions; |
||||
|
++resNumTransitions; |
||||
|
} |
||||
|
|
||||
|
return storm::storage::SparseMatrixBuilder<typename SparseModelType::ValueType>(resNumActions, resNumStates, resNumTransitions, true, true, resNumStates); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
template <typename SparseModelType> |
||||
|
storm::storage::SparseMatrix<typename SparseModelType::ValueType> GoalStateMerger<SparseModelType>::buildTransitionMatrix(storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& sinkStates, boost::optional<uint_fast64_t> const& newTargetState, boost::optional<uint_fast64_t>const& newSinkState, storm::storage::SparseMatrixBuilder<typename SparseModelType::ValueType>& builder) { |
||||
|
|
||||
|
// Get a Mapping that yields for each column in the old matrix the corresponding column in the new matrix
|
||||
|
std::vector<uint_fast64_t> oldToNewIndexMap(maybeStates.size(), std::numeric_limits<uint_fast64_t>::max()); // init with some invalid state
|
||||
|
uint_fast64_t newStateIndex = 0; |
||||
|
for (auto maybeState : maybeStates) { |
||||
|
oldToNewIndexMap[maybeState] = newStateIndex; |
||||
|
++newStateIndex; |
||||
|
} |
||||
|
|
||||
|
// Build the transition matrix
|
||||
|
storm::storage::SparseMatrix<typename SparseModelType::ValueType> const& origMatrix = originalModel.getTransitionMatrix(); |
||||
|
uint_fast64_t currRow = 0; |
||||
|
for (auto state : maybeStates) { |
||||
|
builder.newRowGroup(currRow); |
||||
|
boost::optional<typename SparseModelType::ValueType> targetProbability, sinkProbability; |
||||
|
auto const& endOfRowGroup = origMatrix.getRowGroupIndices()[state+1]; |
||||
|
for (uint_fast64_t row = origMatrix.getRowGroupIndices()[state]; row < endOfRowGroup; ++row) { |
||||
|
for (auto const& entry : origMatrix.getRow(row)) { |
||||
|
if(maybeStates.get(entry.getColumn())) { |
||||
|
builder.addNextValue(currRow, oldToNewIndexMap[entry.getColumn()], entry.getValue()); |
||||
|
} else if (targetStates.get(entry.getColumn())) { |
||||
|
targetProbability = targetProbability.is_initialized() ? *targetProbability + entry.getValue() : entry.getValue(); |
||||
|
} else if (sinkStates.get(entry.getColumn())) { |
||||
|
sinkProbability = sinkProbability.is_initialized() ? *sinkProbability + entry.getValue() : entry.getValue(); |
||||
|
} else { |
||||
|
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "There is a transition originating from a maybestate that does not lead to a maybe-, target-, or sinkstate."); |
||||
|
} |
||||
|
} |
||||
|
if(targetProbability) { |
||||
|
assert(newTargetState); |
||||
|
builder.addNextValue(currRow, *newTargetState, storm::utility::simplify(*targetProbability)); |
||||
|
} |
||||
|
if(sinkProbability) { |
||||
|
assert(newSinkState); |
||||
|
builder.addNextValue(currRow, *newSinkState, storm::utility::simplify(*sinkProbability)); |
||||
|
} |
||||
|
++currRow; |
||||
|
} |
||||
|
} |
||||
|
// Add the selfloops at target and sink
|
||||
|
if(newTargetState) { |
||||
|
builder.newRowGroup(currRow); |
||||
|
builder.addNextValue(currRow, *newTargetState, storm::utility::one<typename SparseModelType::ValueType>()); |
||||
|
++currRow; |
||||
|
} |
||||
|
if(newSinkState) { |
||||
|
builder.newRowGroup(currRow); |
||||
|
builder.addNextValue(currRow, *newSinkState, storm::utility::one<typename SparseModelType::ValueType>()); |
||||
|
++currRow; |
||||
|
} |
||||
|
|
||||
|
return builder.build(); |
||||
|
} |
||||
|
|
||||
|
template class GoalStateMerger<storm::models::sparse::Dtmc<double>>; |
||||
|
template class GoalStateMerger<storm::models::sparse::Mdp<double>>; |
||||
|
template class GoalStateMerger<storm::models::sparse::Dtmc<storm::RationalNumber>>; |
||||
|
template class GoalStateMerger<storm::models::sparse::Mdp<storm::RationalNumber>>; |
||||
|
template class GoalStateMerger<storm::models::sparse::Dtmc<storm::RationalFunction>>; |
||||
|
template class GoalStateMerger<storm::models::sparse::Mdp<storm::RationalFunction>>; |
||||
|
|
||||
|
|
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue