17template<
typename PomdpType>
21template<
typename PomdpType>
27template<
typename PomdpType>
34template<
typename PomdpType>
35std::vector<typename PreprocessingPomdpValueBoundsModelChecker<PomdpType>::PomdpValueType>
36PreprocessingPomdpValueBoundsModelChecker<PomdpType>::getChoiceValues(std::vector<PomdpValueType>
const& stateValues,
37 std::vector<PomdpValueType>* actionBasedRewards) {
38 std::vector<PomdpValueType> choiceValues((
pomdp.getNumberOfChoices()));
39 pomdp.getTransitionMatrix().multiplyWithVector(stateValues, choiceValues, actionBasedRewards);
43template<
typename PomdpType>
44std::pair<std::vector<typename PreprocessingPomdpValueBoundsModelChecker<PomdpType>::PomdpValueType>,
46PreprocessingPomdpValueBoundsModelChecker<PomdpType>::computeValuesForGuessedScheduler(
47 storm::Environment const& env, std::vector<PomdpValueType>
const& stateValues, std::vector<PomdpValueType>* actionBasedRewards,
53 auto choiceValues = getChoiceValues(stateValues, actionBasedRewards);
54 auto const& choiceIndices =
pomdp.getTransitionMatrix().getRowGroupIndices();
55 std::vector<storm::storage::Distribution<PomdpValueType, uint_fast64_t>> choiceDistributions(
pomdp.getNrObservations());
56 for (uint64_t state = 0; state <
pomdp.getNumberOfStates(); ++state) {
57 auto& choiceDistribution = choiceDistributions[
pomdp.getObservation(state)];
58 PomdpValueType
const& stateValue = stateValues[state];
60 for (
auto choice = choiceIndices[state]; choice < choiceIndices[state + 1]; ++choice) {
61 PomdpValueType
const& choiceValue = choiceValues[choice];
68 choiceDistribution.addProbability(choice - choiceIndices[state], scoreThreshold);
70 PomdpValueType choiceScore = info.
minimize() ? (choiceValue - stateValue) : (stateValue - choiceValue);
78 if (choiceScore >= scoreThreshold) {
79 choiceDistribution.addProbability(choice - choiceIndices[state], choiceScore);
84 if (choiceDistribution.size() == 0) {
85 for (
auto choice = choiceIndices[state]; choice < choiceIndices[state + 1]; ++choice) {
86 choiceDistribution.addProbability(choice - choiceIndices[state], scoreThreshold);
89 STORM_LOG_ASSERT(choiceDistribution.size() > 0,
"Empty choice distribution.");
92 for (
auto& choiceDistribution : choiceDistributions) {
93 choiceDistribution.normalize();
96 for (uint64_t state = 0; state < pomdp.getNumberOfStates(); ++state) {
97 pomdpScheduler.setChoice(choiceDistributions[pomdp.getObservation(state)], state);
99 STORM_LOG_ASSERT(!pomdpScheduler.isPartialScheduler(),
"Expected a fully defined scheduler.");
100 auto scheduledModel = underlyingMdp->applyScheduler(pomdpScheduler,
false);
104 STORM_LOG_THROW(resultPtr, storm::exceptions::UnexpectedException,
"No check result obtained.");
105 STORM_LOG_THROW(resultPtr->isExplicitQuantitativeCheckResult(), storm::exceptions::UnexpectedException,
"Unexpected Check result Type.");
106 std::vector<PomdpValueType> pomdpSchedulerResult = resultPtr->template asExplicitQuantitativeCheckResult<PomdpValueType>().getSentinelValueVector();
107 return std::make_pair(pomdpSchedulerResult, pomdpScheduler);
110template<
typename PomdpType>
111std::pair<std::vector<typename PreprocessingPomdpValueBoundsModelChecker<PomdpType>::PomdpValueType>,
112 storm::storage::Scheduler<typename PreprocessingPomdpValueBoundsModelChecker<PomdpType>::PomdpValueType>>
113PreprocessingPomdpValueBoundsModelChecker<PomdpType>::computeValuesForRandomFMPolicy(storm::Environment
const& env, storm::logic::Formula
const& formula,
114 storm::pomdp::analysis::FormulaInformation
const& info,
115 uint64_t memoryBound) {
117 storm::storage::Scheduler<PomdpValueType> pomdpScheduler(pomdp.getNumberOfStates() * memoryBound);
119 STORM_LOG_DEBUG(
"Computing the unfolding for memory bound " << memoryBound);
121 storm::transformer::PomdpMemoryUnfolder<PomdpValueType> memoryUnfolder(pomdp, memory);
123 auto memPomdp = memoryUnfolder.transform(
false);
126 std::vector<uint64_t> obsChoiceVector(memPomdp->getNrObservations());
127 std::random_device rd;
128 auto engine = std::mt19937(rd());
129 for (uint64_t obs = 0; obs < memPomdp->getNrObservations(); ++obs) {
130 uint64_t nrChoices = memPomdp->getNumberOfChoices(memPomdp->getStatesWithObservation(obs).front());
131 std::uniform_int_distribution<uint64_t> uniform_dist(0, nrChoices - 1);
132 obsChoiceVector[obs] = uniform_dist(engine);
134 for (uint64_t state = 0; state < memPomdp->getNumberOfStates(); ++state) {
135 pomdpScheduler.setChoice(obsChoiceVector[memPomdp->getObservation(state)], state);
139 auto underlyingMdp = std::make_shared<storm::models::sparse::Mdp<PomdpValueType>>(memPomdp->getTransitionMatrix(), memPomdp->getStateLabeling(),
140 memPomdp->getRewardModels());
141 auto scheduledModel = underlyingMdp->applyScheduler(pomdpScheduler,
false);
144 STORM_LOG_THROW(resultPtr, storm::exceptions::UnexpectedException,
"No check result obtained.");
145 STORM_LOG_THROW(resultPtr->isExplicitQuantitativeCheckResult(), storm::exceptions::UnexpectedException,
"Unexpected Check result Type.");
146 std::vector<PomdpValueType> pomdpSchedulerResult = resultPtr->template asExplicitQuantitativeCheckResult<PomdpValueType>().getSentinelValueVector();
150 storm::storage::BitVector hasValue(pomdp.getNumberOfStates(),
false);
151 for (uint64_t memPomdpState = 0; memPomdpState < pomdpSchedulerResult.size(); ++memPomdpState) {
152 uint64_t modelState = memPomdpState / memoryBound;
153 if (!hasValue.get(modelState) || (info.
minimize() && pomdpSchedulerResult[memPomdpState] < res[modelState]) ||
154 (!info.
minimize() && pomdpSchedulerResult[memPomdpState] > res[modelState])) {
155 res[modelState] = pomdpSchedulerResult[memPomdpState];
156 hasValue.set(modelState);
159 return std::make_pair(res, pomdpScheduler);
162template<
typename PomdpType>
163[[maybe_unused]] std::pair<std::vector<typename PreprocessingPomdpValueBoundsModelChecker<PomdpType>::PomdpValueType>,
164 storm::storage::Scheduler<typename PreprocessingPomdpValueBoundsModelChecker<PomdpType>::PomdpValueType>>
165PreprocessingPomdpValueBoundsModelChecker<PomdpType>::computeValuesForRandomMemorylessPolicy(
166 storm::Environment
const& env, storm::logic::Formula
const& formula, storm::pomdp::analysis::FormulaInformation
const& info,
167 std::shared_ptr<storm::models::sparse::Mdp<PomdpValueType>> underlyingMdp) {
168 storm::storage::Scheduler<PomdpValueType> pomdpScheduler(pomdp.getNumberOfStates());
169 std::vector<uint64_t> obsChoiceVector(pomdp.getNrObservations());
171 std::random_device rd;
172 auto engine = std::mt19937(rd());
173 for (uint64_t obs = 0; obs < pomdp.getNrObservations(); ++obs) {
174 uint64_t nrChoices = pomdp.getNumberOfChoices(pomdp.getStatesWithObservation(obs).front());
175 std::uniform_int_distribution<uint64_t> uniform_dist(0, nrChoices - 1);
176 obsChoiceVector[obs] = uniform_dist(engine);
179 for (uint64_t state = 0; state < pomdp.getNumberOfStates(); ++state) {
180 STORM_LOG_DEBUG(
"State " << state <<
" -- Random Choice " << obsChoiceVector[pomdp.getObservation(state)]);
181 pomdpScheduler.setChoice(obsChoiceVector[pomdp.getObservation(state)], state);
184 auto scheduledModel = underlyingMdp->applyScheduler(pomdpScheduler,
false);
188 STORM_LOG_THROW(resultPtr, storm::exceptions::UnexpectedException,
"No check result obtained.");
189 STORM_LOG_THROW(resultPtr->isExplicitQuantitativeCheckResult(), storm::exceptions::UnexpectedException,
"Unexpected Check result Type.");
190 std::vector<PomdpValueType> pomdpSchedulerResult = resultPtr->template asExplicitQuantitativeCheckResult<PomdpValueType>().getSentinelValueVector();
192 STORM_LOG_DEBUG(
"Initial Value for guessed Policy: " << pomdpSchedulerResult[pomdp.getInitialStates().getNextSetIndex(0)]);
194 return std::make_pair(pomdpSchedulerResult, pomdpScheduler);
197template<
typename PomdpType>
201 "The property type is not supported for this analysis.");
207 std::make_shared<storm::models::sparse::Mdp<PomdpValueType>>(pomdp.getTransitionMatrix(), pomdp.getStateLabeling(), pomdp.getRewardModels());
210 STORM_LOG_THROW(resultPtr, storm::exceptions::UnexpectedException,
"No check result obtained.");
211 STORM_LOG_THROW(resultPtr->isExplicitQuantitativeCheckResult(), storm::exceptions::UnexpectedException,
"Unexpected Check result Type.");
212 std::vector<PomdpValueType> fullyObservableResult = resultPtr->template asExplicitQuantitativeCheckResult<PomdpValueType>().getSentinelValueVector();
214 std::vector<PomdpValueType> actionBasedRewards;
215 std::vector<PomdpValueType>* actionBasedRewardsPtr =
nullptr;
217 actionBasedRewards = pomdp.getRewardModel(info.
getRewardModelName()).getTotalRewardVector(pomdp.getTransitionMatrix());
218 actionBasedRewardsPtr = &actionBasedRewards;
220 std::vector<std::vector<PomdpValueType>> guessedSchedulerValues;
221 std::vector<storm::storage::Scheduler<PomdpValueType>> guessedSchedulers;
223 std::vector<std::pair<double, bool>> guessParameters({{0.875,
false}, {0.875,
true}, {0.75,
false}, {0.75,
true}});
224 for (
auto const&
pars : guessParameters) {
226 computeValuesForGuessedScheduler(env, fullyObservableResult, actionBasedRewardsPtr, formula, info, underlyingMdp,
228 guessedSchedulerValues.push_back(guessedSchedulerPair->first);
229 guessedSchedulers.push_back(guessedSchedulerPair->second);
233 uint64_t bestGuess = 0;
236 for (uint64_t guess = 1; guess < guessedSchedulerValues.size(); ++guess) {
239 if ((info.
minimize() && guessSum < bestGuessSum) || (info.
maximize() && guessSum > bestGuessSum)) {
241 bestGuessSum = guessSum;
245 computeValuesForGuessedScheduler(env, guessedSchedulerValues[bestGuess], actionBasedRewardsPtr, formula, info, underlyingMdp,
247 guessedSchedulerValues.push_back(guessedSchedulerPair->first);
248 guessedSchedulers.push_back(guessedSchedulerPair->second);
250 computeValuesForGuessedScheduler(env, guessedSchedulerValues.back(), actionBasedRewardsPtr, formula, info, underlyingMdp,
252 guessedSchedulerValues.push_back(guessedSchedulerPair->first);
253 guessedSchedulers.push_back(guessedSchedulerPair->second);
255 computeValuesForGuessedScheduler(env, guessedSchedulerValues.back(), actionBasedRewardsPtr, formula, info, underlyingMdp,
257 guessedSchedulerValues.push_back(guessedSchedulerPair->first);
258 guessedSchedulers.push_back(guessedSchedulerPair->second);
263 for (uint64_t i = 0; i < guessedSchedulerValues.size() - 1; ++i) {
264 if (!keptGuesses.
get(i)) {
267 for (uint64_t j = i + 1; j < guessedSchedulerValues.size(); ++j) {
268 if (!keptGuesses.
get(j)) {
274 keptGuesses.
set(j,
false);
277 keptGuesses.
set(i,
false);
282 keptGuesses.
set(i,
false);
285 keptGuesses.
set(j,
false);
292 std::vector<storm::storage::Scheduler<PomdpValueType>> filteredSchedulers;
293 for (uint64_t i = 0; i < guessedSchedulers.size(); ++i) {
294 if (keptGuesses[i]) {
295 filteredSchedulers.push_back(guessedSchedulers[i]);
302 result.
lower.push_back(std::move(fullyObservableResult));
303 result.
upper = std::move(guessedSchedulerValues);
306 result.
lower = std::move(guessedSchedulerValues);
307 result.
upper.push_back(std::move(fullyObservableResult));
311 bool boundsValid =
true;
313 for (
auto const& lower : result.
lower) {
314 for (
auto const& upper : result.
upper) {
315 for (uint64_t state = 0; state < pomdp.getNumberOfStates(); ++state) {
319 STORM_LOG_TRACE(
"Lower bound " << lower.at(state) <<
" at state " << state <<
" is larger than upper bound " << upper.at(state));
327 <<
"). This might be due to floating point imprecisions. Enable TRACE output for more details.");
333template<
typename PomdpType>
340template<
typename PomdpType>
346template<
typename PomdpType>
360 auto formulaPtr = std::make_shared<storm::logic::RewardOperatorFormula>(newFormula);
362 std::make_shared<storm::models::sparse::Mdp<PomdpValueType>>(pomdp.getTransitionMatrix(), pomdp.getStateLabeling(), pomdp.getRewardModels());
364 STORM_LOG_THROW(resultPtr, storm::exceptions::UnexpectedException,
"No check result obtained.");
365 STORM_LOG_THROW(resultPtr->isExplicitQuantitativeCheckResult(), storm::exceptions::UnexpectedException,
"Unexpected Check result Type.");
366 std::vector<PomdpValueType> resultVec = resultPtr->template asExplicitQuantitativeCheckResult<PomdpValueType>().getSentinelValueVector();
374 res.
values = std::move(resultVec);