20 bool dropUnreachableStates) {
25 if (dropUnreachableStates) {
31 std::vector<std::vector<ObservationType>> stateObservations(mdp.
getNumberOfStates());
34 stateObservations[initState].push_back(initialObservation);
38 std::vector<ObservationType> transitionTargetObservations;
39 transitionTargetObservations.reserve(transitionMatrix.getEntryCount());
40 for (
auto state : retainedStates) {
41 auto const firstChoice = transitionMatrix.getRowGroupIndices()[state];
42 for (
auto choice : transitionMatrix.getRowGroupIndices(state)) {
43 for (
auto const& entry : transitionMatrix.getRow(choice)) {
47 auto const obs = transitionObservationFunction(state, choice - firstChoice, entry.getColumn());
48 transitionTargetObservations.push_back(obs);
49 auto& obsSet = stateObservations[entry.getColumn()];
50 if (std::find(obsSet.begin(), obsSet.end(), obs) == obsSet.end()) {
51 obsSet.push_back(obs);
58 std::vector<uint64_t> stateOffsets;
60 stateOffsets.push_back(0);
61 for (uint64_t offset = 0;
auto& obsSet : stateObservations) {
63 if (!dropUnreachableStates && obsSet.empty()) {
64 obsSet.push_back(initialObservation);
66 offset += obsSet.size();
67 stateOffsets.push_back(offset);
72 auto transTargetObsIt = transitionTargetObservations.begin();
73 uint64_t rowInResultMatrix = 0;
74 for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) {
75 auto const transTargetObsBegin = transTargetObsIt;
76 for (
auto _ [[maybe_unused]] : stateObservations[state]) {
77 transTargetObsIt = transTargetObsBegin;
79 for (
auto choice : transitionMatrix.getRowGroupIndices(state)) {
80 for (
auto const& entry : transitionMatrix.getRow(choice)) {
84 auto const targetObs = *transTargetObsIt;
85 auto const& targetObsSet = stateObservations[entry.getColumn()];
86 auto const findIt = std::find(targetObsSet.begin(), targetObsSet.end(), targetObs);
87 STORM_LOG_ASSERT(findIt != targetObsSet.end(),
"Transition target observation not found in target state.");
88 auto transitionTarget = stateOffsets[entry.getColumn()] + std::distance(targetObsSet.begin(), findIt);
89 matrixBuilder.
addNextValue(rowInResultMatrix, transitionTarget, entry.getValue());
97 uint64_t
const numResultStates = stateOffsets.back();
98 uint64_t
const numResultChoices = rowInResultMatrix;
104 auto forEachState = [&stateOffsets](
auto const& f) {
105 for (uint64_t ogState = 0; ogState < stateOffsets.size() - 1; ++ogState) {
106 for (uint64_t resultState = stateOffsets[ogState]; resultState < stateOffsets[ogState + 1]; ++resultState) {
107 f(resultState, ogState);
111 auto forEachChoice = [&stateOffsets, &transitionMatrix, &components](
auto const& f) {
112 for (uint64_t ogState = 0; ogState < stateOffsets.size() - 1; ++ogState) {
113 for (uint64_t resultState = stateOffsets[ogState]; resultState < stateOffsets[ogState + 1]; ++resultState) {
115 "Number of choices in unfolding and original model differ.");
116 auto ogChoice = transitionMatrix.getRowGroupIndices()[ogState];
117 for (
auto resultChoice : components.
transitionMatrix.getRowGroupIndices(resultState)) {
118 f(resultChoice, ogChoice);
128 auto const& obsSet = stateObservations[ogInitState];
129 auto const findIt = std::find(obsSet.begin(), obsSet.end(), initialObservation);
130 STORM_LOG_ASSERT(findIt != obsSet.end(),
"Initial observation not found in initial state.");
131 auto const resultInitState = stateOffsets[ogInitState] + std::distance(obsSet.begin(), findIt);
132 initialStates.
set(resultInitState);
136 if (label ==
"init") {
141 forEachState([&newLabel, &originalLabel](uint64_t resultState,
StateIdType ogState) {
142 if (originalLabel.get(ogState)) {
143 newLabel.
set(resultState);
155 forEachChoice([&newLabel, &originalLabel](uint64_t unfoldingChoice, uint64_t originalChoice) {
156 if (originalLabel.get(originalChoice)) {
157 newLabel.
set(unfoldingChoice);
166 STORM_LOG_THROW(!rewmodel.hasTransitionRewards(), storm::exceptions::NotSupportedException,
167 "Transition rewards are currently not supported in this context.");
168 std::optional<std::vector<ValueType>> stateRewards, stateActionRewards;
169 if (rewmodel.hasStateRewards()) {
170 stateRewards.emplace();
171 stateRewards->reserve(numResultStates);
173 [&stateRewards, &rewmodel](uint64_t _,
StateIdType originalState) { stateRewards->push_back(rewmodel.getStateReward(originalState)); });
175 if (rewmodel.hasStateActionRewards()) {
176 stateActionRewards.emplace();
177 stateActionRewards->reserve(numResultChoices);
178 forEachChoice([&stateActionRewards, &rewmodel](uint64_t _,
StateIdType originalChoice) {
179 stateActionRewards->push_back(rewmodel.getStateActionReward(originalChoice));
186 std::vector<ObservationType> flatStateObservations;
187 flatStateObservations.reserve(numResultStates);
188 for (
auto const& obsSet : stateObservations) {
189 flatStateObservations.insert(flatStateObservations.end(), obsSet.begin(), obsSet.end());
194 ->template as<storm::models::sparse::Pomdp<ValueType>>();
200 STORM_LOG_THROW(
pomdp.getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::NotSupportedException,
201 "The model must have exactly one initial state.");
202 auto const initialObservation =
pomdp.getObservation(
pomdp.getInitialStates().getNextSetIndex(0));
204 struct TransitionObservation {
206 std::vector<ValueType> rewards;
207 bool operator<(TransitionObservation
const& other)
const {
208 if (targetStateObservation != other.targetStateObservation) {
209 return targetStateObservation < other.targetStateObservation;
211 return rewards < other.rewards;
214 std::map<TransitionObservation, ObservationType> observationIndexStorage;
217 auto getOrAddObservationIndex = [&observationIndexStorage, &freshObservation](TransitionObservation
const& obs) {
218 auto [it, inserted] = observationIndexStorage.try_emplace(obs, freshObservation);
227 auto const globalChoice =
pomdp.getTransitionMatrix().getRowGroupIndices()[srcState] + action;
228 TransitionObservation obs{
pomdp.getObservation(targetState), {}};
229 for (
auto const& rewName : observableRewardModels) {
230 auto const& rewModel =
pomdp.getRewardModel(rewName);
232 if (rewModel.hasStateRewards()) {
233 obs.rewards.back() += rewModel.getStateReward(srcState);
235 if (rewModel.hasStateActionRewards()) {
236 obs.rewards.back() += rewModel.getStateActionReward(globalChoice);
238 STORM_LOG_THROW(!rewModel.hasTransitionRewards(), storm::exceptions::NotSupportedException,
239 "Transition rewards are currently not supported in this context.");
241 return getOrAddObservationIndex(obs);
243 initialObservation, dropUnreachableStates);
244 result->setIsCanonic(
pomdp.isCanonic());