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>
45std::pair<typename GoalStateMerger<SparseModelType>::ReturnType, uint_fast64_t> GoalStateMerger<SparseModelType>::initialize(
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>
117storm::storage::SparseMatrix<typename SparseModelType::ValueType> GoalStateMerger<SparseModelType>::buildTransitionMatrix(
118 storm::storage::BitVector
const& maybeStates, ReturnType
const& resultData, uint_fast64_t transitionCount)
const {
119 storm::storage::SparseMatrix<typename SparseModelType::ValueType>
const& origMatrix = originalModel.getTransitionMatrix();
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);
124 storm::storage::SparseMatrixBuilder<typename SparseModelType::ValueType> builder(
127 uint_fast64_t currRow = 0;
128 for (
auto state : maybeStates) {
130 builder.newRowGroup(currRow);
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);
167 if (resultData.sinkState) {
169 builder.newRowGroup(currRow);
175 return builder.build();
178template<
typename SparseModelType>
179storm::models::sparse::StateLabeling GoalStateMerger<SparseModelType>::buildStateLabeling(storm::storage::BitVector
const& maybeStates,
180 storm::storage::BitVector
const& targetStates,
181 storm::storage::BitVector
const& sinkStates,
182 ReturnType
const& resultData)
const {
183 uint_fast64_t stateCount = maybeStates.
getNumberOfSetBits() + (resultData.targetState ? 1 : 0) + (resultData.sinkState ? 1 : 0);
184 storm::models::sparse::StateLabeling labeling(stateCount);
186 for (
auto const& label : originalModel.getStateLabeling().getLabels()) {
187 storm::storage::BitVector
const& oldStatesWithLabel = originalModel.getStates(label);
188 storm::storage::BitVector newStatesWithLabel = oldStatesWithLabel % maybeStates;
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()) {
221 std::optional<std::vector<RewardValueType>> stateActionRewards;
222 if (origRewardModel.hasStateActionRewards()) {
227 std::optional<storm::storage::SparseMatrix<RewardValueType>> transitionRewards;
228 if (origRewardModel.hasTransitionRewards()) {
229 storm::storage::SparseMatrixBuilder<RewardValueType> builder(choiceCount, stateCount, 0,
true);
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))));
263 storm::storage::BitVector
const& maybeStates, ReturnType
const& resultData, storm::storage::SparseMatrix<double>&& transitionMatrix,
264 storm::models::sparse::StateLabeling&& labeling,
266 storm::storage::sparse::ModelComponents<double> modelComponents(std::move(transitionMatrix), std::move(labeling), std::move(rewardModels));
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);
275 return std::make_shared<storm::models::sparse::MarkovAutomaton<double>>(std::move(modelComponents));
279std::shared_ptr<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>
281 storm::storage::BitVector
const& maybeStates, ReturnType
const& resultData, storm::storage::SparseMatrix<storm::RationalNumber>&& transitionMatrix,
282 storm::models::sparse::StateLabeling&& labeling,
284 storm::storage::sparse::ModelComponents<storm::RationalNumber> modelComponents(std::move(transitionMatrix), std::move(labeling), std::move(rewardModels));
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);
293 return std::make_shared<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>(std::move(modelComponents));
296template<
typename SparseModelType>
297std::shared_ptr<SparseModelType> GoalStateMerger<SparseModelType>::buildOutputModel(
298 storm::storage::BitVector
const&,
GoalStateMerger::ReturnType const&, storm::storage::SparseMatrix<typename SparseModelType::ValueType>&& transitionMatrix,
299 storm::models::sparse::StateLabeling&& labeling, std::unordered_map<std::string, typename SparseModelType::RewardModelType>&& rewardModels)
const {
300 return std::make_shared<SparseModelType>(std::move(transitionMatrix), std::move(labeling), std::move(rewardModels));
CRewardModelType RewardModelType
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 holds a possibly non-square matrix in the compressed row storage format.
const_rows getRow(index_type row) const
Returns an object representing the given row.
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)