20namespace transformer {
22template<
typename SparseModelType>
27template<
typename SparseModelType>
30 std::vector<std::string>
const& selectedRewardModels, boost::optional<storm::storage::BitVector>
const& choiceFilter)
const {
32 storm::exceptions::InvalidArgumentException,
33 "maybestates, targetstates, and sinkstates are assumed to be disjoint when creating the submodel. However, this is not the case.");
35 auto result = initialize(maybeStates, targetStates, sinkStates, choiceFilter);
37 auto transitionMatrix = buildTransitionMatrix(maybeStates, result.first, result.second);
38 auto labeling = buildStateLabeling(maybeStates, targetStates, sinkStates, result.first);
39 auto rewardModels = buildRewardModels(maybeStates, result.first, selectedRewardModels);
41 result.first.model = buildOutputModel(maybeStates, result.first, std::move(transitionMatrix), std::move(labeling), std::move(rewardModels));
46template<
typename SparseModelType>
49 boost::optional<storm::storage::BitVector>
const& choiceFilter)
const {
54 result.oldToNewStateIndexMapping =
55 std::vector<uint_fast64_t>(maybeStates.
size(), std::numeric_limits<uint_fast64_t>::max());
57 uint_fast64_t transitionCount(0), stateCount(0);
58 bool targetStateRequired = !originalModel.getInitialStates().isDisjointFrom(targetStates);
59 bool sinkStateRequired = !originalModel.getInitialStates().isDisjointFrom(sinkStates);
60 for (
auto state : maybeStates) {
61 result.oldToNewStateIndexMapping[state] = stateCount;
64 bool stateIsDeadlock =
true;
65 for (uint_fast64_t row = origMatrix.
getRowGroupIndices()[state]; row < endOfRowGroup; ++row) {
66 uint_fast64_t transitionsToMaybeStates = 0;
67 bool keepThisRow(
true), hasTransitionToTarget(
false), hasTransitionToSink(
false);
68 if (!choiceFilter || choiceFilter.get().get(row)) {
69 for (
auto const& entry : origMatrix.getRow(row)) {
70 if (maybeStates.
get(entry.getColumn())) {
71 ++transitionsToMaybeStates;
72 }
else if (targetStates.
get(entry.getColumn())) {
73 hasTransitionToTarget =
true;
74 }
else if (sinkStates.
get(entry.getColumn())) {
75 hasTransitionToSink =
true;
82 stateIsDeadlock =
false;
83 result.keptChoices.set(row,
true);
84 transitionCount += transitionsToMaybeStates;
85 if (hasTransitionToTarget) {
87 targetStateRequired =
true;
89 if (hasTransitionToSink) {
91 sinkStateRequired =
true;
96 STORM_LOG_THROW(!stateIsDeadlock, storm::exceptions::InvalidArgumentException,
"Merging goal states leads to deadlocks!");
101 if (targetStateRequired) {
102 result.targetState = stateCount;
108 if (sinkStateRequired) {
109 result.sinkState = stateCount;
115 return std::make_pair(std::move(result), std::move(transitionCount));
118template<
typename SparseModelType>
123 uint_fast64_t rowCount = resultData.keptChoices.getNumberOfSetBits() + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
125 uint_fast64_t stateCount = maybeStateCount + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
129 uint_fast64_t currRow = 0;
130 for (
auto state : maybeStates) {
135 for (uint_fast64_t row = resultData.keptChoices.getNextSetIndex(origMatrix.
getRowGroupIndices()[state]); row < endOfRowGroup;
136 row = resultData.keptChoices.getNextSetIndex(row + 1)) {
137 boost::optional<typename SparseModelType::ValueType> targetValue, sinkValue;
138 for (
auto const& entry : origMatrix.getRow(row)) {
139 uint_fast64_t
const& newColumn = resultData.oldToNewStateIndexMapping[entry.getColumn()];
140 if (newColumn < maybeStateCount) {
141 builder.addNextValue(currRow, newColumn, entry.getValue());
142 }
else if (resultData.targetState && newColumn == resultData.targetState.get()) {
143 targetValue = targetValue.is_initialized() ? *targetValue + entry.getValue() : entry.getValue();
144 }
else if (resultData.sinkState && newColumn == resultData.sinkState.get()) {
145 sinkValue = sinkValue.is_initialized() ? *sinkValue + entry.getValue() : entry.getValue();
148 "There is a transition originating from a maybestate that does not lead to a maybe-, target-, or sinkstate.");
162 if (resultData.targetState) {
164 builder.newRowGroup(currRow);
166 builder.addNextValue(currRow, *resultData.targetState, storm::utility::one<typename SparseModelType::ValueType>());
169 if (resultData.sinkState) {
171 builder.newRowGroup(currRow);
173 builder.addNextValue(currRow, *resultData.sinkState, storm::utility::one<typename SparseModelType::ValueType>());
177 return builder.build();
180template<
typename SparseModelType>
184 ReturnType
const& resultData)
const {
185 uint_fast64_t stateCount = maybeStates.
getNumberOfSetBits() + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
188 for (
auto const& label : originalModel.getStateLabeling().getLabels()) {
191 newStatesWithLabel.
resize(stateCount,
false);
192 if (!oldStatesWithLabel.
isDisjointFrom(targetStates) && resultData.targetState.is_initialized()) {
193 newStatesWithLabel.
set(*resultData.targetState,
true);
195 if (!oldStatesWithLabel.
isDisjointFrom(sinkStates) && resultData.sinkState.is_initialized()) {
196 newStatesWithLabel.
set(*resultData.sinkState,
true);
198 labeling.addLabel(label, std::move(newStatesWithLabel));
204template<
typename SparseModelType>
205std::unordered_map<std::string, typename SparseModelType::RewardModelType> GoalStateMerger<SparseModelType>::buildRewardModels(
206 storm::storage::BitVector const& maybeStates, ReturnType
const& resultData, std::vector<std::string>
const& selectedRewardModels)
const {
207 typedef typename SparseModelType::RewardModelType::ValueType RewardValueType;
210 uint_fast64_t stateCount = maybeStateCount + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
211 uint_fast64_t choiceCount = resultData.keptChoices.getNumberOfSetBits() + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
213 std::unordered_map<std::string, typename SparseModelType::RewardModelType> rewardModels;
214 for (
auto rewardModelName : selectedRewardModels) {
215 auto origRewardModel = originalModel.getRewardModel(rewardModelName);
217 std::optional<std::vector<RewardValueType>> stateRewards;
218 if (origRewardModel.hasStateRewards()) {
220 stateRewards->resize(stateCount, storm::utility::zero<RewardValueType>());
223 std::optional<std::vector<RewardValueType>> stateActionRewards;
224 if (origRewardModel.hasStateActionRewards()) {
226 stateActionRewards->resize(choiceCount, storm::utility::zero<RewardValueType>());
229 std::optional<storm::storage::SparseMatrix<RewardValueType>> transitionRewards;
230 if (origRewardModel.hasTransitionRewards()) {
232 for (
auto row : resultData.keptChoices) {
233 boost::optional<typename SparseModelType::ValueType> targetValue, sinkValue;
234 for (
auto const& entry : origRewardModel.getTransitionRewardMatrix().getRow(row)) {
235 uint_fast64_t
const& newColumn = resultData.oldToNewStateIndexMapping[entry.getColumn()];
236 if (newColumn < maybeStateCount) {
237 builder.addNextValue(row, newColumn, entry.getValue());
238 }
else if (resultData.targetState && newColumn == resultData.targetState.get()) {
239 targetValue = targetValue.is_initialized() ? *targetValue + entry.getValue() : entry.getValue();
240 }
else if (resultData.sinkState && newColumn == resultData.sinkState.get()) {
241 sinkValue = sinkValue.is_initialized() ? *sinkValue + entry.getValue() : entry.getValue();
244 "There is a transition reward originating from a maybestate that does not lead to a maybe-, target-, or sinkstate.");
254 transitionRewards = builder.build();
257 rewardModels.insert(std::make_pair(
258 rewardModelName,
typename SparseModelType::RewardModelType(std::move(stateRewards), std::move(stateActionRewards), std::move(transitionRewards))));
264std::shared_ptr<storm::models::sparse::MarkovAutomaton<double>> GoalStateMerger<storm::models::sparse::MarkovAutomaton<double>>::buildOutputModel(
269 uint_fast64_t stateCount = maybeStates.
getNumberOfSetBits() + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
271 modelComponents.markovianStates = originalModel.getMarkovianStates() % maybeStates;
272 modelComponents.markovianStates->
resize(stateCount,
true);
275 modelComponents.exitRates->resize(stateCount, storm::utility::one<double>());
277 return std::make_shared<storm::models::sparse::MarkovAutomaton<double>>(std::move(modelComponents));
281std::shared_ptr<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>
282GoalStateMerger<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::buildOutputModel(
287 uint_fast64_t stateCount = maybeStates.
getNumberOfSetBits() + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
289 modelComponents.markovianStates = originalModel.getMarkovianStates() % maybeStates;
290 modelComponents.markovianStates->
resize(stateCount,
true);
293 modelComponents.exitRates->resize(stateCount, storm::utility::one<storm::RationalNumber>());
295 return std::make_shared<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>(std::move(modelComponents));
298template<
typename SparseModelType>
299std::shared_ptr<SparseModelType> GoalStateMerger<SparseModelType>::buildOutputModel(
302 return std::make_shared<SparseModelType>(std::move(transitionMatrix), std::move(labeling), std::move(rewardModels));
305template class GoalStateMerger<storm::models::sparse::Dtmc<double>>;
306template class GoalStateMerger<storm::models::sparse::Mdp<double>>;
307template class GoalStateMerger<storm::models::sparse::MarkovAutomaton<double>>;
308template class GoalStateMerger<storm::models::sparse::Dtmc<storm::RationalNumber>>;
309template class GoalStateMerger<storm::models::sparse::Mdp<storm::RationalNumber>>;
310template class GoalStateMerger<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>;
311template class GoalStateMerger<storm::models::sparse::Dtmc<storm::RationalFunction>>;
312template 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 ...
void resize(uint_fast64_t newLength, bool init=false)
Resizes the bit vector to hold the given new number of bits.
void set(uint_fast64_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.
uint_fast64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
bool get(uint_fast64_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)