28 STORM_LOG_THROW(!rewardModelNames.empty(), storm::exceptions::IllegalArgumentException,
29 "Reward-aware belief exploration requires at least one selected reward model.");
30 for (
auto const& rewardBound : propertyInformation.
rewardBounds) {
32 STORM_LOG_THROW(!rewardBound.rewardModelName.empty(), storm::exceptions::NotSupportedException,
33 "For POMDPs, reward-bounded formulae must explicitly name a reward model for each bound.");
35 !(propertyInformation.
dir == storm::OptimizationDirection::Minimize && rewardBound.lowerBound.has_value() && rewardBound.upperBound.has_value()),
36 storm::exceptions::NotSupportedException,
37 "Reward-bounded probability minimisation does not support dimensions with both lower and upper reward bounds.");
40 "The selected reward models must include all reward-bounded dimensions first.");
41 for (std::size_t i = 0; i < propertyInformation.
rewardBounds.size(); ++i) {
43 rewardModelNames[i] == propertyInformation.
rewardBounds[i].rewardModelName, storm::exceptions::IllegalArgumentException,
44 "Selected reward model " << i <<
" must match the corresponding reward bound '" << propertyInformation.
rewardBounds[i].rewardModelName <<
"'.");
48template<
typename PomdpModelType,
typename BeliefValueType,
typename BeliefMdpValueType>
50 STORM_LOG_THROW(inputPomdp.isCanonic(), storm::exceptions::IllegalArgumentException,
"Belief-based model checking requires a canonic POMDP.");
54template<
typename PomdpModelType,
typename BeliefType,
typename BeliefMdpValueType,
typename InfoType>
59 return [&info, maxSize = options.
maxExplorationSize.value()]() {
return info.discoveredBeliefs.getNumberOfBeliefIds() > maxSize; };
64 return info.discoveredBeliefs.getNumberOfBeliefIds() > maxSize || swExplore.getTimeInSeconds() >
static_cast<double>(maxDuration);
68 return []() {
return false; };
70 STORM_LOG_ERROR(
"Unknown termination criterion for belief exploration.");
71 return []() {
return false; };
80template<
typename PomdpModelType,
typename BeliefType,
typename BeliefMdpValueType>
84 using PomdpValueType =
typename PomdpModelType::ValueType;
88 return [&propertyInformation, &valueBounds](BeliefType
const& belief) -> std::optional<BeliefMdpValueType> {
93 for (
auto const& valueList : valueBounds.
upper) {
94 smallestUpper = std::min(smallestUpper, belief.template getWeightedSum<PomdpValueType>(valueList));
97 for (
auto const& valueList : valueBounds.
lower) {
98 largestLower =
storm::utility::max(largestLower, belief.template getWeightedSum<PomdpValueType>(valueList));
101 if constexpr (std::is_same_v<PomdpValueType, BeliefMdpValueType>) {
102 return propertyInformation.
dir == solver::OptimizationDirection::Maximize ? largestLower : smallestUpper;
105 propertyInformation.
dir == solver::OptimizationDirection::Maximize ? largestLower : smallestUpper);
112 return [&propertyInformation](BeliefType
const& belief) -> std::optional<BeliefMdpValueType> {
121 return [](BeliefType
const& belief) -> std::optional<BeliefMdpValueType> {
129 return [&propertyInformation, &valueBounds](BeliefType
const& belief) -> std::optional<BeliefMdpValueType> {
134 for (
auto const& valueList : valueBounds.
upper) {
135 smallestUpper = std::min(smallestUpper, belief.template getWeightedSum<PomdpValueType>(valueList));
138 for (
auto const& valueList : valueBounds.
lower) {
139 largestLower =
storm::utility::max(largestLower, belief.template getWeightedSum<PomdpValueType>(valueList));
142 if constexpr (std::is_same_v<PomdpValueType, BeliefMdpValueType>) {
143 return propertyInformation.
dir == solver::OptimizationDirection::Maximize ? largestLower : smallestUpper;
146 propertyInformation.
dir == solver::OptimizationDirection::Maximize ? largestLower : smallestUpper);
153 return [&propertyInformation](BeliefType
const& belief) -> std::optional<BeliefMdpValueType> {
168template<
typename PomdpModelType,
typename BeliefType,
typename BeliefMdpValueType,
typename InfoType>
169std::pair<std::shared_ptr<models::sparse::Mdp<BeliefMdpValueType>>, std::unordered_map<uint64_t, BeliefId>>
buildBeliefMdpFromInfo(
171 InfoType
const& info) {
172 using PomdpValueType =
typename PomdpModelType::ValueType;
173 std::function<std::unordered_map<std::string, BeliefMdpValueType>(BeliefType
const&)> computeCutOffValueMap =
174 [&valueBounds, &propertyInformation](BeliefType
const& belief) {
176 uint64_t
const nrCutoffPolicies =
177 propertyInformation.
dir == storm::OptimizationDirection::Minimize ? valueBounds.
upper.size() : valueBounds.
lower.size();
178 std::unordered_map<std::string, BeliefMdpValueType> result;
179 for (uint64_t i = 0; i < nrCutoffPolicies; ++i) {
180 auto val = belief.template getWeightedSum<PomdpValueType>(
181 propertyInformation.
dir == storm::OptimizationDirection::Minimize ? valueBounds.
upper.at(i) : valueBounds.
lower.at(i));
182 if constexpr (std::is_same_v<PomdpValueType, BeliefMdpValueType>) {
183 result[
"__sched_" + std::to_string(i)] = val;
190 return buildBeliefMdp(info, propertyInformation, computeCutOffValueMap);
193template<
typename PomdpModelType,
typename BeliefType,
typename BeliefMdpValueType,
typename AbstractionType,
199 BeliefBasedModelCheckerStatistics statistics;
202 "Unexpected kind of property.");
207 using BeliefExplorationType = BeliefExploration<BeliefMdpValueType, PomdpModelType, BeliefType>;
209 BeliefExplorationType exploration(
pomdp);
215 typename BeliefExplorationType::TerminationCallback terminationCallback =
219 typename BeliefExplorationType::TerminalBeliefCallback terminalBeliefCallback =
222 if constexpr (std::is_same_v<InfoType, ClippingExplorationInformation<BeliefMdpValueType, BeliefType>>) {
225 exploration.resumeClippingExploration(info, terminalBeliefCallback, terminationCallback, propertyInformation.
rewardModelName.value(), abstraction);
227 exploration.resumeClippingExploration(info, terminalBeliefCallback, terminationCallback,
storm::NullRef, abstraction);
234 "Clipping for expected total reachability reward requires extreme value bounds to be given.");
235 ClippingBeliefAbstraction<BeliefType> clippingAbstraction(
236 env, std::move(resolutions), std::move(valueBounds.
extremeBounds->template copyValues<typename BeliefType::ValueType>()));
237 exploration.resumeClippingExploration(
241 exploration.resumeClippingExploration(
247 exploration.resumeExploration(info, terminalBeliefCallback, terminationCallback, propertyInformation.
rewardModelName.value(), abstraction);
249 exploration.resumeExploration(info, terminalBeliefCallback, terminationCallback,
storm::NullRef, abstraction);
253 bool earlyExplorationStop = info.queue.hasNext();
254 statistics.completedExploration = !earlyExplorationStop;
255 statistics.discoveredBeliefs = info.discoveredBeliefs.getNumberOfBeliefIds();
256 statistics.exploredBeliefs = info.exploredBeliefs.size();
257 statistics.explorationTimeMilliseconds = swExplore.getTimeInMilliseconds();
258 if (earlyExplorationStop) {
259 STORM_LOG_INFO(
"Exploration stopped before all beliefs were explored. " << info.discoveredBeliefs.getNumberOfBeliefIds() <<
" beliefs discovered. "
260 << info.exploredBeliefs.size() <<
" beliefs explored.");
265 storm::utility::Stopwatch swBuild(
true);
266 auto [beliefMdp, stateToBeliefMap] =
270 std::stringstream stream;
271 beliefMdp->printModelInformationToStream(stream);
274 statistics.beliefMdpStates = beliefMdp->getNumberOfStates();
275 statistics.beliefMdpChoices = beliefMdp->getNumberOfChoices();
276 statistics.beliefMdpTransitions = beliefMdp->getNumberOfTransitions();
277 statistics.beliefMdpBuildTimeMilliseconds = swBuild.getTimeInMilliseconds();
280 storm::utility::Stopwatch swCheck(
true);
282 storm::modelchecker::CheckTask<storm::logic::Formula, BeliefMdpValueType> task(*formula,
true);
285 statistics.beliefMdpAnalysisTimeMilliseconds = swCheck.getTimeInMilliseconds();
286 STORM_LOG_INFO(
"Time for exploring beliefs: " << swExplore <<
".");
287 STORM_LOG_INFO(
"Time for building the belief MDP: " << swBuild <<
".");
288 STORM_LOG_INFO(
"Time for analyzing the belief MDP: " << swCheck <<
".");
289 STORM_LOG_ASSERT(res,
"Model checking of belief MDP did not return any result.");
290 STORM_LOG_ASSERT(res->isExplicitQuantitativeCheckResult(),
"Model checking of belief MDP did not return result of expected type.");
291 STORM_LOG_ASSERT(beliefMdp->getInitialStates().getNumberOfSetBits() == 1,
"Unexpected number of initial states for belief Mdp.");
292 auto const initState = beliefMdp->getInitialStates().getNextSetIndex(0);
293 return {res->asExplicitQuantitativeCheckResult<BeliefMdpValueType>()[initState], !earlyExplorationStop, std::move(statistics)};
296template<
typename PomdpModelType,
typename BeliefType,
typename BeliefMdpValueType>
303 BeliefBasedModelCheckerStatistics statistics;
305 STORM_LOG_THROW(!options.
useClipping, storm::exceptions::NotSupportedException,
"Grid clipping is not supported for reward-bounded POMDP properties.");
311 using BeliefExplorationType = BeliefExploration<BeliefMdpValueType, PomdpModelType, BeliefType>;
313 BeliefExplorationType exploration(
pomdp);
319 typename BeliefExplorationType::TerminationCallback terminationCallback =
323 typename BeliefExplorationType::TerminalBeliefCallback terminalBeliefCallback =
326 exploration.resumeRewardAwareExploration(info, terminalBeliefCallback, terminationCallback, rewardSplitter, abstraction);
328 bool const earlyExplorationStop = info.queue.hasNext();
329 statistics.completedExploration = !earlyExplorationStop;
330 statistics.discoveredBeliefs = info.discoveredBeliefs.getNumberOfBeliefIds();
331 statistics.exploredBeliefs = info.exploredBeliefs.size();
332 statistics.explorationTimeMilliseconds = swExplore.getTimeInMilliseconds();
333 if (earlyExplorationStop) {
334 STORM_LOG_INFO(
"Exploration stopped before all beliefs were explored. " << info.discoveredBeliefs.getNumberOfBeliefIds() <<
" beliefs discovered. "
335 << info.exploredBeliefs.size() <<
" beliefs explored.");
341 auto [beliefMdp, stateToBeliefMap] =
345 std::stringstream stream;
346 beliefMdp->printModelInformationToStream(stream);
349 statistics.beliefMdpStates = beliefMdp->getNumberOfStates();
350 statistics.beliefMdpChoices = beliefMdp->getNumberOfChoices();
351 statistics.beliefMdpTransitions = beliefMdp->getNumberOfTransitions();
352 statistics.beliefMdpBuildTimeMilliseconds = swBuild.getTimeInMilliseconds();
356 STORM_LOG_INFO(
"Analyzing property '" << *formula <<
"' on the belief MDP.");
358 std::shared_ptr<storm::models::sparse::Mdp<BeliefMdpValueType>> processedMdp = beliefMdp;
360 std::vector<std::string> rewardModelNames;
361 for (
auto const& bnd : propertyInformation.
rewardBounds) {
362 rewardModelNames.push_back(bnd.rewardModelName);
365 .model->template as<storm::models::sparse::Mdp<BeliefMdpValueType>>();
366 double increase =
static_cast<double>(processedMdp->getNumberOfStates()) /
static_cast<double>(beliefMdp->getNumberOfStates());
367 STORM_LOG_INFO(
"Transformation of transition rewards resulted in a model with " << processedMdp->getNumberOfStates() <<
" states. " << increase
368 <<
" times more states than the original belief MDP.");
371 auto targetStates = processedMdp->getStateLabeling().getStates(
"target");
372 storm::storage::BitVector allStates(targetStates.size(),
true);
373 storm::storage::BitVector probGreaterZeroStates;
377 probGreaterZeroStates =
379 processedMdp->getBackwardTransitions(), allStates, targetStates);
381 auto mergingResult = storm::transformer::GoalStateMerger<BeliefMdpValueType>(*processedMdp)
382 .mergeTargetAndSinkStates(probGreaterZeroStates, ~probGreaterZeroStates, ~allStates, rewardModelNames);
383 processedMdp = mergingResult.model->template as<storm::models::sparse::Mdp<BeliefMdpValueType>>();
384 STORM_LOG_INFO(
"Merging of sink states resulted in a model with " << processedMdp->getNumberOfStates() <<
" states.");
386 if (processedMdp != beliefMdp) {
387 statistics.processedMdpStates = processedMdp->getNumberOfStates();
388 statistics.processedMdpChoices = processedMdp->getNumberOfChoices();
389 statistics.processedMdpTransitions = processedMdp->getNumberOfTransitions();
391 storm::modelchecker::CheckTask<storm::logic::Formula, BeliefMdpValueType> task(*formula,
true);
394 statistics.beliefMdpAnalysisTimeMilliseconds = swCheck.getTimeInMilliseconds();
395 STORM_LOG_INFO(
"Time for exploring beliefs: " << swExplore <<
".");
396 STORM_LOG_INFO(
"Time for building the belief MDP: " << swBuild <<
".");
397 STORM_LOG_INFO(
"Time for analyzing the belief MDP: " << swCheck <<
".");
398 STORM_LOG_ASSERT(res,
"Model checking of belief MDP did not return any result.");
399 STORM_LOG_ASSERT(res->isExplicitQuantitativeCheckResult(),
"Model checking of belief MDP did not return result of expected type.");
400 STORM_LOG_ASSERT(processedMdp->getInitialStates().getNumberOfSetBits() == 1,
"Unexpected number of initial states for (processed) belief Mdp.");
401 auto const initState = processedMdp->getInitialStates().getNextSetIndex(0);
402 return {res->asExplicitQuantitativeCheckResult<BeliefMdpValueType>()[initState], !earlyExplorationStop, std::move(statistics)};
405template<
typename PomdpModelType,
typename BeliefValueType,
typename BeliefMdpValueType>
413 options, valueBounds);
416 options, valueBounds);
420template<
typename PomdpModelType,
typename BeliefValueType,
typename BeliefMdpValueType>
426 "Belief discretization does not support exploration size or time limits.");
433template<
typename PomdpModelType,
typename BeliefValueType,
typename BeliefMdpValueType>
442 valueBounds, rewardBoundedBeliefSplitter);
445template<
typename PomdpModelType,
typename BeliefValueType,
typename BeliefMdpValueType>
451 "Belief discretization does not support exploration size or time limits.");
458 env, inputPomdp, propertyInformation, options, valueBounds, rewardBoundedBeliefSplitter, abstraction);
Helper class that optionally holds a reference to an object of type T.
Builds and checks a finite belief MDP approximation of a POMDP.
BeliefBasedModelChecker(PomdpModelType const &pomdp)
Creates a checker for a canonic POMDP.
BeliefBasedModelCheckerResult< BeliefMdpValueType > checkRewardAwareDiscretize(storm::Environment const &env, PropertyInformation const &propertyInformation, storm::pomdp::beliefs::BeliefBasedModelCheckerOptions< BeliefMdpValueType > const &options, uint64_t resolution, bool useDynamic, storage::BeliefExplorationBounds< typename PomdpModelType::ValueType > const &valueBounds, std::vector< std::string > const &relevantRewardModelNames)
Combines reward-aware exploration with Freudenthal triangulation discretization.
BeliefBasedModelCheckerResult< BeliefMdpValueType > checkDiscretize(storm::Environment const &env, PropertyInformation const &propertyInformation, storm::pomdp::beliefs::BeliefBasedModelCheckerOptions< BeliefMdpValueType > const &options, uint64_t resolution, bool useDynamic, storage::BeliefExplorationBounds< PomdpValueType > const &valueBounds)
Explores the belief space and discretises beliefs using the Freudenthal triangualtion approximation.
BeliefBasedModelCheckerResult< BeliefMdpValueType > checkUnfold(storm::Environment const &env, PropertyInformation const &propertyInformation, BeliefBasedModelCheckerOptions< BeliefMdpValueType > const &options, storage::BeliefExplorationBounds< PomdpValueType > const &valueBounds)
Explores the belief MDP by unfolding the belief space.
BeliefBasedModelCheckerResult< BeliefMdpValueType > checkRewardAwareUnfold(storm::Environment const &env, PropertyInformation const &propertyInformation, storm::pomdp::beliefs::BeliefBasedModelCheckerOptions< BeliefMdpValueType > const &options, storage::BeliefExplorationBounds< typename PomdpModelType::ValueType > const &valueBounds, std::vector< std::string > const &relevantRewardModelNames)
Explores a reward-aware belief MDP, splitting beliefs before successor generation by their reward vec...
std::function< bool()> TerminationCallback
std::function< std::optional< BeliefMdpValueType >(BeliefType const &)> TerminalBeliefCallback
Approximates a belief by clipping it to an observation-specific grid point.
Abstracts a belief by triangulating it using the Freudenthal triangulation.
Abstracts a given belief by splitting it into sub-beliefs based on the (state-action) reward of the P...
std::size_t getNumberOfSetRewardModels() const
void setRewardModels(std::vector< std::string > const &rewardModelNames)
Selects a nonempty list of reward models used to form reward vectors.
A class that provides convenience operations to display run times.
SecondType getTimeInSeconds() const
Gets the measured time in seconds.
#define STORM_LOG_INFO(message)
#define STORM_LOG_TRACE(message)
#define STORM_LOG_ERROR(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
std::unique_ptr< storm::modelchecker::CheckResult > verifyWithSparseEngine(storm::Environment const &env, std::shared_ptr< storm::models::sparse::Dtmc< ValueType > > const &dtmc, storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &task, bool preferEliminationChecker=false)
std::pair< std::shared_ptr< models::sparse::Mdp< BeliefMdpValueType > >, std::unordered_map< uint64_t, BeliefId > > buildBeliefMdpFromInfo(PropertyInformation const &propertyInformation, storm::pomdp::storage::PreprocessingPomdpValueBounds< typename PomdpModelType::ValueType > const &valueBounds, InfoType const &info)
Converts exploration information into a finite MDP.
BeliefBasedModelCheckerResult< BeliefMdpValueType > checkUnfoldOrDiscretize(storm::Environment const &env, PomdpModelType const &pomdp, PropertyInformation const &propertyInformation, storm::pomdp::beliefs::BeliefBasedModelCheckerOptions< BeliefMdpValueType > const &options, storage::BeliefExplorationBounds< typename PomdpModelType::ValueType > const &valueBounds, storm::OptionalRef< AbstractionType > abstraction={})
BeliefBasedModelCheckerResult< BeliefMdpValueType > checkRewardAwareUnfoldOrDiscretize(storm::Environment const &env, PomdpModelType const &pomdp, PropertyInformation const &propertyInformation, storm::pomdp::beliefs::BeliefBasedModelCheckerOptions< BeliefMdpValueType > const &options, storage::BeliefExplorationBounds< typename PomdpModelType::ValueType > const &valueBounds, RewardBoundedBeliefSplitter< BeliefMdpValueType, PomdpModelType, BeliefType > &rewardSplitter, storm::OptionalRef< FreudenthalTriangulationBeliefAbstraction< BeliefType > > abstraction={})
void validateRewardModelSelection(PropertyInformation const &propertyInformation, std::vector< std::string > const &rewardModelNames)
BeliefExploration< BeliefMdpValueType, PomdpModelType, BeliefType >::TerminationCallback getTerminationCallback(storm::pomdp::beliefs::BeliefBasedModelCheckerOptions< BeliefMdpValueType > const &options, InfoType &info, storm::utility::Stopwatch &swExplore)
Creates the callback that ends exploration and turns the queued beliefs into the frontier.
std::shared_ptr< storm::logic::Formula const > createFormulaForBeliefMdp(PropertyInformation const &propertyInformation)
ExplorationInformation< BeliefMdpValueType, BeliefType, std::optional< BeliefMdpValueType >, std::optional< BeliefMdpValueType > > ClippingExplorationInformation
Exploration information that stores optional clipping probability and reward-adjustment metadata.
ExplorationInformation< BeliefMdpValueType, BeliefType > StandardExplorationInformation
Exploration information without transition metadata.
@ MAX_EXPLORATION_SIZE_AND_TIME
BeliefExploration< BeliefMdpValueType, PomdpModelType, BeliefType >::TerminalBeliefCallback getTerminalBeliefCallback(PropertyInformation const &propertyInformation, storm::pomdp::beliefs::BeliefBasedModelCheckerOptions< BeliefMdpValueType > const &options, storm::pomdp::storage::PreprocessingPomdpValueBounds< typename PomdpModelType::ValueType > const &valueBounds)
Creates a callback that recognizes property targets and optional zero-gap cut-offs as terminal belief...
std::pair< std::shared_ptr< models::sparse::Mdp< BeliefMdpValueType > >, std::unordered_map< uint64_t, BeliefId > > buildBeliefMdp(ExplorationInformation< BeliefMdpValueType, BeliefType, ExtraTransitionData... > const &explorationInformation, PropertyInformation const &propertyInformation, std::function< std::unordered_map< std::string, BeliefMdpValueType >(BeliefType const &)> const &computeCutOffValueMap)
Builds a belief MDP from the given exploration information and property information.
ExplorationInformation< BeliefMdpValueType, BeliefType, std::vector< BeliefMdpValueType > > RewardAwareExplorationInformation
Exploration information that stores a reward vector on each transition.
bool constexpr maximize(OptimizationDirection d)
storm::storage::BitVector performProbGreater0A(storm::storage::SparseMatrix< T > const &transitionMatrix, std::vector< uint_fast64_t > const &nondeterministicChoiceIndices, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps, boost::optional< storm::storage::BitVector > const &choiceConstraint)
Computes the sets of states that have probability greater 0 of satisfying phi until psi under any pos...
storm::storage::BitVector performProbGreater0E(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps)
Computes the sets of states that have probability greater 0 of satisfying phi until psi under at leas...
ValueType max(ValueType const &first, ValueType const &second)
ValueType abs(ValueType const &number)
TargetType convertNumber(SourceType const &number)
OptionalRef(T &) -> OptionalRef< T >
deduction guides
constexpr NullRefType NullRef
std::optional< std::vector< uint64_t > > clippingResolutions
std::optional< uint64_t > maxExplorationTime
ExplorationQueueOrder explorationQueueOrder
bool cutZeroGap
Cut non-target beliefs only when their preprocessing lower and upper bounds have exactly zero gap.
std::optional< uint64_t > maxExplorationSize
explorationTerminationCriterion getTerminationCriterion() const
Get the termination criterion for the exploration.
Result of a belief-based model-checking run.
Auxiliary struct used to identify cases where no abstraction of beliefs shall be applied.
Struct for storing precomputed values bounding the actual values on the POMDP.
std::optional< ExtremePOMDPValueBound< POMDPValueType > > extremeBounds
std::optional< PreprocessingPomdpValueBounds< POMDPValueType > > preprocessingBounds
Struct for storing precomputed values bounding the actual values on the POMDP.
std::vector< std::vector< POMDPValueType > > lower
std::vector< std::vector< POMDPValueType > > upper