18namespace transformer {
20template<
typename SparseModelType>
25template<
typename SparseModelType>
28 std::vector<std::string>
const& selectedRewardModels, boost::optional<storm::storage::BitVector>
const& choiceFilter)
const {
30 storm::exceptions::InvalidArgumentException,
31 "maybestates, targetstates, and sinkstates are assumed to be disjoint when creating the submodel. However, this is not the case.");
33 auto result = initialize(maybeStates, targetStates, sinkStates, choiceFilter);
35 auto transitionMatrix = buildTransitionMatrix(maybeStates, result.first, result.second);
36 auto labeling = buildStateLabeling(maybeStates, targetStates, sinkStates, result.first);
37 auto rewardModels = buildRewardModels(maybeStates, result.first, selectedRewardModels);
39 result.first.model = buildOutputModel(maybeStates, result.first, std::move(transitionMatrix), std::move(labeling), std::move(rewardModels));
44template<
typename SparseModelType>
47 boost::optional<storm::storage::BitVector>
const& choiceFilter)
const {
52 result.oldToNewStateIndexMapping =
53 std::vector<uint_fast64_t>(maybeStates.
size(), std::numeric_limits<uint_fast64_t>::max());
55 uint_fast64_t transitionCount(0), stateCount(0);
56 bool targetStateRequired = !originalModel.getInitialStates().isDisjointFrom(targetStates);
57 bool sinkStateRequired = !originalModel.getInitialStates().isDisjointFrom(sinkStates);
58 for (
auto state : maybeStates) {
59 result.oldToNewStateIndexMapping[state] = stateCount;
62 bool stateIsDeadlock =
true;
63 for (uint_fast64_t row = origMatrix.
getRowGroupIndices()[state]; row < endOfRowGroup; ++row) {
64 uint_fast64_t transitionsToMaybeStates = 0;
65 bool keepThisRow(
true), hasTransitionToTarget(
false), hasTransitionToSink(
false);
66 if (!choiceFilter || choiceFilter.get().get(row)) {
67 for (
auto const& entry : origMatrix.getRow(row)) {
68 if (maybeStates.
get(entry.getColumn())) {
69 ++transitionsToMaybeStates;
70 }
else if (targetStates.
get(entry.getColumn())) {
71 hasTransitionToTarget =
true;
72 }
else if (sinkStates.
get(entry.getColumn())) {
73 hasTransitionToSink =
true;
80 stateIsDeadlock =
false;
81 result.keptChoices.set(row,
true);
82 transitionCount += transitionsToMaybeStates;
83 if (hasTransitionToTarget) {
85 targetStateRequired =
true;
87 if (hasTransitionToSink) {
89 sinkStateRequired =
true;
94 STORM_LOG_THROW(!stateIsDeadlock, storm::exceptions::InvalidArgumentException,
"Merging goal states leads to deadlocks!");
99 if (targetStateRequired) {
100 result.targetState = stateCount;
106 if (sinkStateRequired) {
107 result.sinkState = stateCount;
113 return std::make_pair(std::move(result), std::move(transitionCount));
116template<
typename SparseModelType>
121 uint_fast64_t rowCount = resultData.keptChoices.getNumberOfSetBits() + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
123 uint_fast64_t stateCount = maybeStateCount + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
127 uint_fast64_t currRow = 0;
128 for (
auto state : maybeStates) {
133 for (uint_fast64_t row = resultData.keptChoices.getNextSetIndex(origMatrix.
getRowGroupIndices()[state]); row < endOfRowGroup;
134 row = resultData.keptChoices.getNextSetIndex(row + 1)) {
135 boost::optional<typename SparseModelType::ValueType> targetValue, sinkValue;
136 for (
auto const& entry : origMatrix.getRow(row)) {
137 uint_fast64_t
const& newColumn = resultData.oldToNewStateIndexMapping[entry.getColumn()];
138 if (newColumn < maybeStateCount) {
139 builder.addNextValue(currRow, newColumn, entry.getValue());
140 }
else if (resultData.targetState && newColumn == resultData.targetState.get()) {
141 targetValue = targetValue.is_initialized() ? *targetValue + entry.getValue() : entry.getValue();
142 }
else if (resultData.sinkState && newColumn == resultData.sinkState.get()) {
143 sinkValue = sinkValue.is_initialized() ? *sinkValue + entry.getValue() : entry.getValue();
146 "There is a transition originating from a maybestate that does not lead to a maybe-, target-, or sinkstate.");
160 if (resultData.targetState) {
162 builder.newRowGroup(currRow);
164 builder.addNextValue(currRow, *resultData.targetState, storm::utility::one<typename SparseModelType::ValueType>());
167 if (resultData.sinkState) {
169 builder.newRowGroup(currRow);
171 builder.addNextValue(currRow, *resultData.sinkState, storm::utility::one<typename SparseModelType::ValueType>());
175 return builder.build();
178template<
typename SparseModelType>
182 ReturnType
const& resultData)
const {
183 uint_fast64_t stateCount = maybeStates.
getNumberOfSetBits() + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
186 for (
auto const& label : originalModel.getStateLabeling().getLabels()) {
189 newStatesWithLabel.
resize(stateCount,
false);
190 if (!oldStatesWithLabel.
isDisjointFrom(targetStates) && resultData.targetState.is_initialized()) {
191 newStatesWithLabel.
set(*resultData.targetState,
true);
193 if (!oldStatesWithLabel.
isDisjointFrom(sinkStates) && resultData.sinkState.is_initialized()) {
194 newStatesWithLabel.
set(*resultData.sinkState,
true);
196 labeling.addLabel(label, std::move(newStatesWithLabel));
202template<
typename SparseModelType>
203std::unordered_map<std::string, typename SparseModelType::RewardModelType> GoalStateMerger<SparseModelType>::buildRewardModels(
204 storm::storage::BitVector const& maybeStates, ReturnType
const& resultData, std::vector<std::string>
const& selectedRewardModels)
const {
205 typedef typename SparseModelType::RewardModelType::ValueType RewardValueType;
208 uint_fast64_t stateCount = maybeStateCount + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
209 uint_fast64_t choiceCount = resultData.keptChoices.getNumberOfSetBits() + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
211 std::unordered_map<std::string, typename SparseModelType::RewardModelType> rewardModels;
212 for (
auto rewardModelName : selectedRewardModels) {
213 auto origRewardModel = originalModel.getRewardModel(rewardModelName);
215 std::optional<std::vector<RewardValueType>> stateRewards;
216 if (origRewardModel.hasStateRewards()) {
218 stateRewards->resize(stateCount, storm::utility::zero<RewardValueType>());
221 std::optional<std::vector<RewardValueType>> stateActionRewards;
222 if (origRewardModel.hasStateActionRewards()) {
224 stateActionRewards->resize(choiceCount, storm::utility::zero<RewardValueType>());
227 std::optional<storm::storage::SparseMatrix<RewardValueType>> transitionRewards;
228 if (origRewardModel.hasTransitionRewards()) {
230 for (
auto row : resultData.keptChoices) {
231 boost::optional<typename SparseModelType::ValueType> targetValue, sinkValue;
232 for (
auto const& entry : origRewardModel.getTransitionRewardMatrix().getRow(row)) {
233 uint_fast64_t
const& newColumn = resultData.oldToNewStateIndexMapping[entry.getColumn()];
234 if (newColumn < maybeStateCount) {
235 builder.addNextValue(row, newColumn, entry.getValue());
236 }
else if (resultData.targetState && newColumn == resultData.targetState.get()) {
237 targetValue = targetValue.is_initialized() ? *targetValue + entry.getValue() : entry.getValue();
238 }
else if (resultData.sinkState && newColumn == resultData.sinkState.get()) {
239 sinkValue = sinkValue.is_initialized() ? *sinkValue + entry.getValue() : entry.getValue();
242 "There is a transition reward originating from a maybestate that does not lead to a maybe-, target-, or sinkstate.");
252 transitionRewards = builder.build();
255 rewardModels.insert(std::make_pair(
256 rewardModelName,
typename SparseModelType::RewardModelType(std::move(stateRewards), std::move(stateActionRewards), std::move(transitionRewards))));
262std::shared_ptr<storm::models::sparse::MarkovAutomaton<double>> GoalStateMerger<storm::models::sparse::MarkovAutomaton<double>>::buildOutputModel(
267 uint_fast64_t stateCount = maybeStates.
getNumberOfSetBits() + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
269 modelComponents.markovianStates = originalModel.getMarkovianStates() % maybeStates;
270 modelComponents.markovianStates->
resize(stateCount,
true);
273 modelComponents.exitRates->resize(stateCount, storm::utility::one<double>());
275 return std::make_shared<storm::models::sparse::MarkovAutomaton<double>>(std::move(modelComponents));
279std::shared_ptr<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>
280GoalStateMerger<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::buildOutputModel(
285 uint_fast64_t stateCount = maybeStates.
getNumberOfSetBits() + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
287 modelComponents.markovianStates = originalModel.getMarkovianStates() % maybeStates;
288 modelComponents.markovianStates->
resize(stateCount,
true);
291 modelComponents.exitRates->resize(stateCount, storm::utility::one<storm::RationalNumber>());
293 return std::make_shared<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>(std::move(modelComponents));
296template<
typename SparseModelType>
297std::shared_ptr<SparseModelType> GoalStateMerger<SparseModelType>::buildOutputModel(
300 return std::make_shared<SparseModelType>(std::move(transitionMatrix), std::move(labeling), std::move(rewardModels));
303template class GoalStateMerger<storm::models::sparse::Dtmc<double>>;
304template class GoalStateMerger<storm::models::sparse::Mdp<double>>;
305template class GoalStateMerger<storm::models::sparse::MarkovAutomaton<double>>;
306template class GoalStateMerger<storm::models::sparse::Dtmc<storm::RationalNumber>>;
307template class GoalStateMerger<storm::models::sparse::Mdp<storm::RationalNumber>>;
308template class GoalStateMerger<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>;
309template class GoalStateMerger<storm::models::sparse::Dtmc<storm::RationalFunction>>;
310template class GoalStateMerger<storm::models::sparse::Mdp<storm::RationalFunction>>;
This class manages the labeling of the state space with a number of (atomic) labels.
A bit vector that is internally represented as a vector of 64-bit values.
bool isDisjointFrom(BitVector const &other) const
Checks whether none of the bits that are set in the current bit vector are also set in the given bit ...
uint64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
size_t size() const
Retrieves the number of bits this bit vector can store.
void resize(uint64_t newLength, bool init=false)
Resizes the bit vector to hold the given new number of bits.
bool get(uint64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
A class that can be used to build a sparse matrix by adding value by value.
void newRowGroup(index_type startingRow)
Starts a new row group in the matrix.
A class that holds a possibly non-square matrix in the compressed row storage format.
bool hasTrivialRowGrouping() const
Retrieves whether the matrix has a trivial row grouping.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
index_type getRowCount() const
Returns the number of rows of the matrix.
#define STORM_LOG_THROW(cond, exception, message)
void setVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< T > const &values)
Sets the provided values at the provided positions in the given vector.
std::vector< Type > filterVector(std::vector< Type > const &in, storm::storage::BitVector const &filter)
ValueType simplify(ValueType value)