1#include "storm-config.h"
23enum class PreprocessingType {
None, SelfloopReduction, QualitativeReduction,
All };
25class DefaultDoubleVIEnvironment {
27 typedef double POMDPValueType;
28 typedef double BeliefValueType;
29 typedef double BeliefMDPValueType;
31 static storm::Environment createEnvironment() {
32 storm::Environment env;
37 static bool const isExactModelChecking =
false;
38 static POMDPValueType precision() {
41 static PreprocessingType
const preprocessingType = PreprocessingType::None;
42 static uint64_t overApproxResolution() {
47class SelfloopReductionDefaultDoubleVIEnvironment {
49 typedef double POMDPValueType;
50 typedef double BeliefValueType;
51 typedef double BeliefMDPValueType;
52 static storm::Environment createEnvironment() {
53 storm::Environment env;
58 static bool const isExactModelChecking =
false;
59 static POMDPValueType precision() {
62 static PreprocessingType
const preprocessingType = PreprocessingType::SelfloopReduction;
63 static uint64_t overApproxResolution() {
68class QualitativeReductionDefaultDoubleVIEnvironment {
70 typedef double POMDPValueType;
71 typedef double BeliefValueType;
72 typedef double BeliefMDPValueType;
73 static storm::Environment createEnvironment() {
74 storm::Environment env;
79 static bool const isExactModelChecking =
false;
80 static POMDPValueType precision() {
83 static PreprocessingType
const preprocessingType = PreprocessingType::QualitativeReduction;
84 static uint64_t overApproxResolution() {
89class PreprocessedDefaultDoubleVIEnvironment {
91 typedef double POMDPValueType;
92 typedef double BeliefValueType;
93 typedef double BeliefMDPValueType;
94 static storm::Environment createEnvironment() {
95 storm::Environment env;
100 static bool const isExactModelChecking =
false;
101 static POMDPValueType precision() {
104 static PreprocessingType
const preprocessingType = PreprocessingType::All;
105 static uint64_t overApproxResolution() {
110class FineDoubleVIEnvironment {
112 typedef double POMDPValueType;
113 typedef double BeliefValueType;
114 typedef double BeliefMDPValueType;
115 static storm::Environment createEnvironment() {
116 storm::Environment env;
121 static bool const isExactModelChecking =
false;
122 static POMDPValueType precision() {
125 static PreprocessingType
const preprocessingType = PreprocessingType::None;
126 static uint64_t overApproxResolution() {
131class DefaultDoubleOVIEnvironment {
133 typedef double POMDPValueType;
134 typedef double BeliefValueType;
135 typedef double BeliefMDPValueType;
136 static storm::Environment createEnvironment() {
137 storm::Environment env;
143 static bool const isExactModelChecking =
false;
144 static POMDPValueType precision() {
147 static PreprocessingType
const preprocessingType = PreprocessingType::None;
148 static uint64_t overApproxResolution() {
153class DefaultDoubleSVIEnvironment {
155 typedef double POMDPValueType;
156 typedef double BeliefValueType;
157 typedef double BeliefMDPValueType;
158 static storm::Environment createEnvironment() {
159 storm::Environment env;
165 static bool const isExactModelChecking =
false;
166 static POMDPValueType precision() {
169 static PreprocessingType
const preprocessingType = PreprocessingType::None;
170 static uint64_t overApproxResolution() {
175class DefaultRationalPIEnvironment {
177 typedef storm::RationalNumber POMDPValueType;
178 typedef storm::RationalNumber BeliefValueType;
179 typedef storm::RationalNumber BeliefMDPValueType;
181 static storm::Environment createEnvironment() {
182 storm::Environment env;
187 static bool const isExactModelChecking =
true;
188 static POMDPValueType precision() {
191 static PreprocessingType
const preprocessingType = PreprocessingType::None;
192 static uint64_t overApproxResolution() {
197class PreprocessedDefaultRationalPIEnvironment {
199 typedef storm::RationalNumber POMDPValueType;
200 typedef storm::RationalNumber BeliefValueType;
201 typedef storm::RationalNumber BeliefMDPValueType;
203 static storm::Environment createEnvironment() {
204 storm::Environment env;
209 static bool const isExactModelChecking =
true;
210 static POMDPValueType precision() {
213 static PreprocessingType
const preprocessingType = PreprocessingType::All;
214 static uint64_t overApproxResolution() {
219template<
typename TestType>
220class BeliefBasedModelCheckerTest :
public ::testing::Test {
222 typedef typename TestType::POMDPValueType POMDPValueType;
223 typedef typename TestType::BeliefValueType BeliefValueType;
224 typedef typename TestType::BeliefMDPValueType BeliefMDPValueType;
227 BeliefBasedModelCheckerTest() : _environment(TestType::createEnvironment()) {}
229 void SetUp()
override {
231 GTEST_SKIP() <<
"Z3 not available.";
235 storm::Environment
const& env()
const {
239 template<
typename ValueType>
244 std::shared_ptr<storm::models::sparse::Pomdp<POMDPValueType>> model;
245 std::shared_ptr<storm::logic::Formula const> formula;
246 std::shared_ptr<storm::pomdp::beliefs::PropertyInformation> propertyInfo = std::make_shared<storm::pomdp::beliefs::PropertyInformation>();
248 Input buildPrism(std::string
const& programFile, std::string
const& formulaAsString, std::string
const& constantsAsString =
"")
const {
251 program = program.
preprocess(constantsAsString);
255 bool const isBoundedProbability =
256 input.formula->isProbabilityOperatorFormula() && input.formula->asProbabilityOperatorFormula().getSubformula().isBoundedUntilFormula();
259 storm::transformer::MakePOMDPCanonic<POMDPValueType> makeCanonic(*input.model);
260 input.model = makeCanonic.transform();
261 EXPECT_TRUE(input.model->isCanonic());
262 if (!isBoundedProbability &&
263 (TestType::preprocessingType == PreprocessingType::SelfloopReduction || TestType::preprocessingType == PreprocessingType::All)) {
264 storm::transformer::GlobalPOMDPSelfLoopEliminator<POMDPValueType> selfLoopEliminator(*input.model);
265 if (selfLoopEliminator.preservesFormula(*input.formula)) {
266 input.model = selfLoopEliminator.transform();
268 EXPECT_TRUE(input.formula->isOperatorFormula());
269 EXPECT_TRUE(input.formula->asOperatorFormula().hasOptimalityType());
272 EXPECT_TRUE(maximizing || input.formula->isProbabilityOperatorFormula());
273 EXPECT_TRUE(!maximizing || input.formula->isRewardOperatorFormula());
276 if (!isBoundedProbability &&
277 (TestType::preprocessingType == PreprocessingType::QualitativeReduction || TestType::preprocessingType == PreprocessingType::All)) {
278 EXPECT_TRUE(input.formula->isOperatorFormula());
279 EXPECT_TRUE(input.formula->asOperatorFormula().hasOptimalityType());
280 if (input.formula->isProbabilityOperatorFormula() &&
storm::solver::maximize(input.formula->asOperatorFormula().getOptimalityType())) {
281 storm::analysis::QualitativeAnalysisOnGraphs<POMDPValueType> qualitativeAnalysis(*input.model);
282 storm::storage::BitVector prob0States = qualitativeAnalysis.analyseProb0(input.formula->asProbabilityOperatorFormula());
283 storm::storage::BitVector prob1States = qualitativeAnalysis.analyseProb1(input.formula->asProbabilityOperatorFormula());
284 storm::pomdp::transformer::KnownProbabilityTransformer<POMDPValueType> kpt;
285 input.model = kpt.
transform(*input.model, prob0States, prob1States);
288 EXPECT_TRUE(input.model->isCanonic());
290 std::optional<std::string> rewardModelName;
291 std::set<uint32_t> targetObservations;
292 EXPECT_TRUE(formulaInfo.isNonNestedReachabilityProbability() || formulaInfo.isNonNestedExpectedRewardFormula());
293 if (formulaInfo.getTargetStates().observationClosed) {
294 targetObservations = formulaInfo.getTargetStates().observations;
296 storm::transformer::MakeStateSetObservationClosed<POMDPValueType> obsCloser(input.model);
297 std::tie(input.model, targetObservations) = obsCloser.transform(formulaInfo.getTargetStates().states);
299 if (formulaInfo.isNonNestedReachabilityProbability()) {
300 if (!formulaInfo.getSinkStates().empty()) {
301 storm::storage::sparse::ModelComponents<POMDPValueType> components;
303 components.
rewardModels = input.model->getRewardModels();
304 auto matrix = input.model->getTransitionMatrix();
305 matrix.makeRowGroupsAbsorbing(formulaInfo.getSinkStates().states);
308 if (input.model->hasChoiceLabeling()) {
311 if (input.model->hasObservationValuations()) {
314 input.model = std::make_shared<storm::models::sparse::Pomdp<POMDPValueType>>(std::move(components),
true);
315 auto reachableFromSinkStates =
317 formulaInfo.getSinkStates().states, ~formulaInfo.getSinkStates().states);
318 reachableFromSinkStates &= ~formulaInfo.getSinkStates().states;
319 STORM_LOG_THROW(reachableFromSinkStates.empty(), storm::exceptions::NotSupportedException,
320 "There are sink states that can reach non-sink states. This is currently not supported");
324 rewardModelName = formulaInfo.getRewardModelName();
327 if (rewardModelName) {
329 input.propertyInfo->rewardModelName = rewardModelName;
330 }
else if (formulaInfo.isBounded()) {
332 auto const& boundedFormula = input.formula->asProbabilityOperatorFormula().getSubformula().asBoundedUntilFormula();
333 for (uint64_t i = 0;
i < boundedFormula.getDimension(); ++
i) {
334 auto const& reference = boundedFormula.getTimeBoundReference(i);
335 input.propertyInfo->rewardBounds.push_back({.rewardModelName = reference.getOptionalRewardModelName().get_value_or(
""),
336 .lowerBound = boundedFormula.getLowerBoundAsOptionalTimeBound(i),
337 .upperBound = boundedFormula.getUpperBoundAsOptionalTimeBound(i)});
342 input.propertyInfo->dir = formulaInfo.getOptimizationDirection();
343 input.propertyInfo->targetObservations = targetObservations;
347 POMDPValueType precision()
const {
348 return TestType::precision();
350 uint64_t overApproxResolution()
const {
351 return TestType::overApproxResolution();
353 template<
typename ValueType>
354 ValueType modelcheckingPrecision()
const {
355 if (TestType::isExactModelChecking) {
361 bool isExact()
const {
362 return TestType::isExactModelChecking;
366 storm::Environment _environment;
369typedef ::testing::Types<DefaultDoubleVIEnvironment, SelfloopReductionDefaultDoubleVIEnvironment, QualitativeReductionDefaultDoubleVIEnvironment,
370 PreprocessedDefaultDoubleVIEnvironment, FineDoubleVIEnvironment, DefaultDoubleOVIEnvironment, DefaultDoubleSVIEnvironment,
371 DefaultRationalPIEnvironment, PreprocessedDefaultRationalPIEnvironment>
376TYPED_TEST(BeliefBasedModelCheckerTest, cut_zero_gap) {
377 using POMDPValueType =
typename TestFixture::POMDPValueType;
378 using BeliefValueType =
typename TestFixture::BeliefValueType;
379 using BeliefMDPValueType =
typename TestFixture::BeliefMDPValueType;
382 auto check = [&](std::string
const& formula, std::string
const& expectedValue) {
383 SCOPED_TRACE(formula);
384 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism", formula,
"slippery=0");
385 ASSERT_EQ(data.model->getInitialStates().getNumberOfSetBits(), 1ul);
386 auto const initialState = data.model->getInitialStates().getNextSetIndex(0);
387 auto const expected = this->
template parseNumber<BeliefMDPValueType>(expectedValue);
388 auto const initialValue = this->
template parseNumber<POMDPValueType>(expectedValue);
389 auto const delta = this->
template parseNumber<POMDPValueType>(
"1/100000000");
394 auto setInitialBounds = [&](POMDPValueType
const& lower, POMDPValueType
const& upper) {
396 values[initialState] = lower;
399 values[initialState] = upper;
407 auto propertyInfo = *data.propertyInfo;
408 for (
int const mode : {0, 1, 2}) {
411 return mode == 0 ? checker.checkUnfold(this->env(), propertyInfo, options, bounds)
412 : checker.checkDiscretize(this->env(), propertyInfo, options, this->overApproxResolution(), mode == 2, bounds);
415 setInitialBounds(initialValue, initialValue);
417 auto const cut = run();
418 EXPECT_TRUE(cut.completedExploration);
419 EXPECT_EQ(cut.statistics.discoveredBeliefs, 1ul);
420 EXPECT_EQ(cut.statistics.exploredBeliefs, 0ul);
421 EXPECT_LE(
storm::utility::abs(cut.value - expected), this->template modelcheckingPrecision<BeliefMDPValueType>());
424 auto const uncut = run();
425 EXPECT_TRUE(uncut.completedExploration);
426 EXPECT_GT(uncut.statistics.discoveredBeliefs, 1ul);
427 EXPECT_GT(uncut.statistics.exploredBeliefs, 0ul);
430 setInitialBounds(initialValue - delta, initialValue + delta);
432 auto const positiveGap = run();
433 EXPECT_TRUE(positiveGap.completedExploration);
434 EXPECT_GT(positiveGap.statistics.discoveredBeliefs, 1ul);
435 EXPECT_GT(positiveGap.statistics.exploredBeliefs, 0ul);
439 check(
"Pmax=? [F \"goal\" ]",
"7/10");
440 check(
"Pmin=? [F \"goal\" ]",
"3/10");
441 check(
"Rmax=? [F s>4 ]",
"29/50");
442 check(
"Rmin=? [F s>4 ]",
"19/50");
445TYPED_TEST(BeliefBasedModelCheckerTest, simple_Pmax) {
447 typedef typename TestFixture::POMDPValueType POMDPValueType;
448 typedef typename TestFixture::BeliefValueType BeliefValueType;
449 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
451 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Pmax=? [F \"goal\" ]",
"slippery=0");
456 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
462 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
463 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
465 auto expected = this->
template parseNumber<BeliefMDPValueType>(
"7/10");
466 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
467 overResultValue = overCheckResult.value;
468 EXPECT_GT(overCheckResult.statistics.discoveredBeliefs, 0ul);
469 EXPECT_GT(overCheckResult.statistics.exploredBeliefs, 0ul);
470 EXPECT_GT(overCheckResult.statistics.beliefMdpStates, 0ul);
471 EXPECT_GT(overCheckResult.statistics.beliefMdpChoices, 0ul);
472 EXPECT_GT(overCheckResult.statistics.beliefMdpTransitions, 0ul);
473 EXPECT_GE(overResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
475 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
476 underResultValue = underCheckResult.value;
477 EXPECT_LE(underResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
479 <<
"Result [" << underResultValue <<
", " << overResultValue
480 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
483TYPED_TEST(BeliefBasedModelCheckerTest, simple_Pmin) {
485 typedef typename TestFixture::POMDPValueType POMDPValueType;
486 typedef typename TestFixture::BeliefValueType BeliefValueType;
487 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
489 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Pmin=? [F \"goal\" ]",
"slippery=0");
494 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
500 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
501 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
503 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"3/10");
504 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
505 overResultValue = overCheckResult.value;
506 EXPECT_LE(overResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
508 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
509 underResultValue = underCheckResult.value;
510 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
512 <<
"Result [" << overResultValue <<
", " << underResultValue
513 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
516TYPED_TEST(BeliefBasedModelCheckerTest, discretization_rejects_exploration_limits) {
517 using POMDPValueType =
typename TestFixture::POMDPValueType;
518 using BeliefValueType =
typename TestFixture::BeliefValueType;
519 using BeliefMDPValueType =
typename TestFixture::BeliefMDPValueType;
522 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Pmin=? [F \"goal\" ]",
"slippery=0");
533 STORM_SILENT_EXPECT_THROW(checker.checkDiscretize(this->env(), *data.propertyInfo, options, 10,
false, bounds), storm::exceptions::NotSupportedException);
535 auto const unfolded = checker.checkUnfold(this->env(), *data.propertyInfo, options, bounds);
536 EXPECT_FALSE(unfolded.completedExploration);
539 auto const discretized = checker.checkDiscretize(this->env(), *data.propertyInfo, options, 10,
false, bounds);
540 EXPECT_TRUE(discretized.completedExploration);
541 EXPECT_GT(discretized.statistics.exploredBeliefs, 1);
544TYPED_TEST(BeliefBasedModelCheckerTest, simple_slippery_Pmax) {
546 typedef typename TestFixture::POMDPValueType POMDPValueType;
547 typedef typename TestFixture::BeliefValueType BeliefValueType;
548 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
550 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Pmax=? [F \"goal\" ]",
"slippery=0.4");
555 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
560 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
561 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
563 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"7/10");
564 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
565 overResultValue = overCheckResult.value;
566 EXPECT_GE(overResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
567 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
569 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
570 underResultValue = underCheckResult.value;
571 EXPECT_LE(underResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
573 <<
"Result [" << underResultValue <<
", " << overResultValue
574 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
577TYPED_TEST(BeliefBasedModelCheckerTest, simple_slippery_Pmin) {
579 typedef typename TestFixture::POMDPValueType POMDPValueType;
580 typedef typename TestFixture::BeliefValueType BeliefValueType;
581 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
583 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Pmin=? [F \"goal\" ]",
"slippery=0.4");
588 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
592 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
593 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
595 POMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"3/10");
596 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
597 overResultValue = overCheckResult.value;
599 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
600 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
601 underResultValue = underCheckResult.value;
602 if (this->isExact()) {
606 EXPECT_GE(underResultValue, expected - approxPrecision);
607 EXPECT_LE(overResultValue, expected + approxPrecision);
609 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
610 EXPECT_LE(overResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
613 <<
"Result [" << underResultValue <<
", " << overResultValue
614 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
617TYPED_TEST(BeliefBasedModelCheckerTest, simple_Rmax) {
619 typedef typename TestFixture::POMDPValueType POMDPValueType;
620 typedef typename TestFixture::BeliefValueType BeliefValueType;
621 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
623 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Rmax=? [F s>4 ]",
"slippery=0");
628 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
633 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
634 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
636 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"29/50");
637 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
638 overResultValue = overCheckResult.value;
639 EXPECT_GE(overResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
641 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
642 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
643 underResultValue = underCheckResult.value;
644 EXPECT_LE(underResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
646 <<
"Result [" << underResultValue <<
", " << overResultValue
647 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
650TYPED_TEST(BeliefBasedModelCheckerTest, simple_Rmin) {
652 typedef typename TestFixture::POMDPValueType POMDPValueType;
653 typedef typename TestFixture::BeliefValueType BeliefValueType;
654 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
656 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Rmin=? [F s>4 ]",
"slippery=0");
661 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
666 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
667 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
669 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"19/50");
670 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
671 overResultValue = overCheckResult.value;
672 EXPECT_LE(overResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
674 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
675 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
676 underResultValue = underCheckResult.value;
677 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
679 <<
"Result [" << overResultValue <<
", " << underResultValue
680 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
683TYPED_TEST(BeliefBasedModelCheckerTest, simple_slippery_Rmax) {
685 typedef typename TestFixture::POMDPValueType POMDPValueType;
686 typedef typename TestFixture::BeliefValueType BeliefValueType;
687 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
689 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Rmax=? [F s>4 ]",
"slippery=0.4");
693 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
698 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
699 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
701 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"29/30");
702 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
703 overResultValue = overCheckResult.value;
704 EXPECT_GE(overResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
706 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
707 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
708 underResultValue = underCheckResult.value;
709 EXPECT_LE(underResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
711 <<
"Result [" << underResultValue <<
", " << overResultValue
712 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
715TYPED_TEST(BeliefBasedModelCheckerTest, simple_slippery_Rmin) {
717 typedef typename TestFixture::POMDPValueType POMDPValueType;
718 typedef typename TestFixture::BeliefValueType BeliefValueType;
719 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
721 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Rmin=? [F s>4 ]",
"slippery=0.4");
726 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
731 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
732 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
734 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"19/30");
735 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
736 overResultValue = overCheckResult.value;
737 EXPECT_LE(overResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
739 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
740 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
741 underResultValue = underCheckResult.value;
742 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
744 <<
"Result [" << overResultValue <<
", " << underResultValue
745 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
748TYPED_TEST(BeliefBasedModelCheckerTest, maze2_Rmin) {
750 typedef typename TestFixture::POMDPValueType POMDPValueType;
751 typedef typename TestFixture::BeliefValueType BeliefValueType;
752 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
754 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"Rmin=? [F \"goal\"]",
"sl=0");
759 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
764 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
765 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
767 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"74/91");
768 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
769 overResultValue = overCheckResult.value;
770 EXPECT_LE(overResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
772 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
773 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
774 underResultValue = underCheckResult.value;
775 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
777 <<
"Result [" << overResultValue <<
", " << underResultValue
778 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
781TYPED_TEST(BeliefBasedModelCheckerTest, maze2_Rmax) {
783 typedef typename TestFixture::POMDPValueType POMDPValueType;
784 typedef typename TestFixture::BeliefValueType BeliefValueType;
785 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
787 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"Rmax=? [F \"goal\"]",
"sl=0");
792 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
797 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
798 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
800 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
801 overResultValue = overCheckResult.value;
804 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
805 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
806 underResultValue = underCheckResult.value;
810TYPED_TEST(BeliefBasedModelCheckerTest, maze2_slippery_Rmin) {
812 typedef typename TestFixture::POMDPValueType POMDPValueType;
813 typedef typename TestFixture::BeliefValueType BeliefValueType;
814 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
816 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"Rmin=? [F \"goal\"]",
"sl=0.075");
821 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
826 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
827 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
829 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"80/91");
830 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
831 overResultValue = overCheckResult.value;
832 EXPECT_LE(overResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
834 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
835 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
836 underResultValue = underCheckResult.value;
837 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
839 <<
"Result [" << overResultValue <<
", " << underResultValue
840 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
843TYPED_TEST(BeliefBasedModelCheckerTest, maze2_slippery_Rmax) {
845 typedef typename TestFixture::POMDPValueType POMDPValueType;
846 typedef typename TestFixture::BeliefValueType BeliefValueType;
847 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
849 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"Rmax=? [F \"goal\"]",
"sl=0.075");
854 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
859 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
860 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
862 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
863 overResultValue = overCheckResult.value;
866 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
867 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
868 underResultValue = underCheckResult.value;
872TYPED_TEST(BeliefBasedModelCheckerTest, refuel_Pmax) {
874 typedef typename TestFixture::POMDPValueType POMDPValueType;
875 typedef typename TestFixture::BeliefValueType BeliefValueType;
876 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
878 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/refuel.prism",
"Pmax=?[\"notbad\" U \"goal\"]",
"N=4");
883 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
888 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
889 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
891 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"38/155");
892 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
893 overResultValue = overCheckResult.value;
894 EXPECT_GE(overResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
896 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
897 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
898 underResultValue = underCheckResult.value;
899 EXPECT_LE(underResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
901 <<
"Result [" << underResultValue <<
", " << overResultValue
902 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
905TYPED_TEST(BeliefBasedModelCheckerTest, refuel_Pmin) {
907 typedef typename TestFixture::POMDPValueType POMDPValueType;
908 typedef typename TestFixture::BeliefValueType BeliefValueType;
909 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
911 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/refuel.prism",
"Pmin=?[\"notbad\" U \"goal\"]",
"N=4");
916 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
921 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
922 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
924 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"0");
925 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
926 overResultValue = overCheckResult.value;
927 EXPECT_LE(overResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
929 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
930 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
931 underResultValue = underCheckResult.value;
932 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
934 <<
"Result [" << overResultValue <<
", " << underResultValue
935 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
938TYPED_TEST(BeliefBasedModelCheckerTest, reward_bounded_simple_min_max) {
940 typedef typename TestFixture::POMDPValueType POMDPValueType;
941 typedef typename TestFixture::BeliefValueType BeliefValueType;
942 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
944 auto check = [
this](std::string
const& formula, std::string
const& expectedValue) {
945 SCOPED_TRACE(formula);
946 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple_unit_rewards.prism", formula,
"slippery=0");
956 std::vector<std::string> rewardModelNames;
957 for (
auto const& rewardBound : data.propertyInfo->rewardBounds) {
958 rewardModelNames.push_back(rewardBound.rewardModelName);
960 auto const expected = this->
template parseNumber<BeliefMDPValueType>(expectedValue);
961 for (
bool const discretize : {
false,
true}) {
962 SCOPED_TRACE(discretize ?
"discretize" :
"unfold");
965 discretize ? checker.checkRewardAwareDiscretize(this->env(), *data.propertyInfo, options, 10,
false, precomputedBeliefBounds, rewardModelNames)
966 : checker.checkRewardAwareUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds, rewardModelNames);
967 EXPECT_TRUE(result.completedExploration);
968 EXPECT_LE(
storm::utility::abs(result.value - expected), this->template modelcheckingPrecision<BeliefMDPValueType>());
973 check(
"Pmax=? [ true Urew{\"rew\"}<=3 \"goal\" ]",
"7/10");
974 check(
"Pmin=? [ true Urew{\"rew\"}<=3 \"goal\" ]",
"3/10");
975 check(
"Pmax=? [ true Urew{\"rew\"}<=2 \"goal\" ]",
"0");
976 check(
"Pmin=? [ true Urew{\"rew\"}<=2 \"goal\" ]",
"0");
978 check(
"Pmax=? [ true Urew{\"rew\"}>=4 \"goal\" ]",
"7/10");
979 check(
"Pmin=? [ true Urew{\"rew\"}>=4 \"goal\" ]",
"3/10");
982TYPED_TEST(BeliefBasedModelCheckerTest, reused_explorer_clears_reward_model) {
985 using BeliefMDPValueType =
typename TestFixture::BeliefMDPValueType;
992 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Rmax=? [F s>4 ]",
"slippery=0");
993 Explorer explorer(*data.model);
994 std::string
const rewardModelName;
995 auto const selectRewardModel = [&]() {
996 auto info = explorer.template initializeExploration<StandardInfo>(data.model->getNrObservations());
998 EXPECT_GT(info.matrix.rows(), 0ul);
999 EXPECT_EQ(info.actionRewards.size(), info.matrix.rows());
1002 selectRewardModel();
1003 auto ordinary = explorer.template initializeExploration<StandardInfo>(data.model->getNrObservations());
1005 EXPECT_GT(ordinary.matrix.rows(), 0ul);
1006 EXPECT_TRUE(ordinary.actionRewards.empty());
1008 selectRewardModel();
1009 auto clipping = explorer.template initializeExploration<ClippingInfo>(data.model->getNrObservations());
1011 EXPECT_GT(clipping.matrix.rows(), 0ul);
1012 EXPECT_TRUE(clipping.actionRewards.empty());
1014 selectRewardModel();
1016 splitter.setRewardModel();
1017 auto rewardAware = explorer.template initializeExploration<RewardAwareInfo>(data.model->getNrObservations());
1019 EXPECT_GT(rewardAware.matrix.rows(), 0ul);
1020 EXPECT_TRUE(rewardAware.actionRewards.empty());
1021 ASSERT_FALSE(rewardAware.matrix.transitions.empty());
1022 for (
auto const& transition : rewardAware.matrix.transitions) {
1023 EXPECT_EQ(transition.data.size(), 1ul);
1027TYPED_TEST(BeliefBasedModelCheckerTest, reward_aware_resume_preserves_observation_indices) {
1030 using BeliefMDPValueType =
typename TestFixture::BeliefMDPValueType;
1037 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Rmax=? [F s>4 ]",
"slippery=0");
1038 Explorer explorer(*data.model);
1039 Splitter uninterruptedSplitter(*data.model);
1040 uninterruptedSplitter.setRewardModel();
1044 Splitter resumedSplitter(*data.model);
1045 resumedSplitter.setRewardModel();
1047 for (uint64_t steps = 0; resumed.queue.hasNext() && steps < 100; ++steps) {
1048 auto const limit = resumed.exploredBeliefs.size() + 1;
1049 explorer.resumeRewardAwareExploration(
1052 ASSERT_FALSE(resumed.queue.hasNext());
1053 ASSERT_EQ(resumed.discoveredBeliefs.getNumberOfBeliefIds(), uninterrupted.discoveredBeliefs.getNumberOfBeliefIds());
1054 for (uint64_t
id = 0;
id < uninterrupted.discoveredBeliefs.getNumberOfBeliefIds(); ++id) {
1055 EXPECT_TRUE(resumed.discoveredBeliefs.containsBelief(uninterrupted.discoveredBeliefs.getBeliefFromId(
id)));
1057 ASSERT_EQ(resumed.matrix.transitions.size(), uninterrupted.matrix.transitions.size());
1058 for (uint64_t i = 0;
i < uninterrupted.matrix.transitions.size(); ++
i) {
1059 auto const& expected = uninterrupted.matrix.transitions[
i];
1060 auto const& actual = resumed.matrix.transitions[
i];
1061 EXPECT_EQ(actual.probability, expected.probability);
1062 EXPECT_EQ(actual.data, expected.data);
1063 EXPECT_EQ(resumed.discoveredBeliefs.getBeliefFromId(actual.targetBelief), uninterrupted.discoveredBeliefs.getBeliefFromId(expected.targetBelief));
1067TYPED_TEST(BeliefBasedModelCheckerTest, reward_bounded_requires_explicit_reward_model_name) {
1068 auto const programFile = STORM_TEST_RESOURCES_DIR
"/pomdp/simple_unit_rewards.prism";
1069 auto data = this->buildPrism(programFile,
"Pmax=? [ true Urew{\"rew\"}<=3 \"goal\" ]",
"slippery=0");
1075 auto unnamedProperty = *data.propertyInfo;
1076 unnamedProperty.rewardBounds.front().rewardModelName.clear();
1078 typename TestFixture::BeliefMDPValueType>
1079 checker(*data.model);
1082 STORM_SILENT_EXPECT_THROW(checker.checkRewardAwareUnfold(this->env(), unnamedProperty, options, bounds, {
"rew"}), storm::exceptions::NotSupportedException);
1085TYPED_TEST(BeliefBasedModelCheckerTest, reward_bounded_requires_matching_reward_model_selection) {
1088 using BeliefMDPValueType =
typename TestFixture::BeliefMDPValueType;
1089 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple_unit_rewards.prism",
"Pmax=? [ true Urew{\"rew\"}<=3 \"goal\" ]",
"slippery=0");
1095 storm::exceptions::IllegalArgumentException);
1096 STORM_SILENT_EXPECT_THROW(checker.checkRewardAwareDiscretize(this->env(), *data.propertyInfo, options, 10,
false, bounds, {}),
1097 storm::exceptions::IllegalArgumentException);
1099 storm::exceptions::IllegalArgumentException);
1100 STORM_SILENT_EXPECT_THROW(checker.checkRewardAwareDiscretize(this->env(), *data.propertyInfo, options, 10,
false, bounds, {
"other",
"rew"}),
1101 storm::exceptions::IllegalArgumentException);
1107TYPED_TEST(BeliefBasedModelCheckerTest, reward_bounded_allows_additional_observed_reward_model) {
1108 using POMDPValueType =
typename TestFixture::POMDPValueType;
1109 using BeliefMDPValueType =
typename TestFixture::BeliefMDPValueType;
1111 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple_unit_rewards.prism",
"Pmax=? [ true Urew{\"rew\"}<=3 \"goal\" ]",
"slippery=0");
1112 auto extraRewardModel = data.model->getRewardModel(
"rew");
1113 data.model->addRewardModel(
"extra", extraRewardModel);
1122 auto const expected = this->
template parseNumber<BeliefMDPValueType>(
"7/10");
1123 for (
bool const discretize : {
false,
true}) {
1124 auto const result = discretize ? checker.checkRewardAwareDiscretize(this->env(), *data.propertyInfo, options, 10,
false, bounds, {
"rew",
"extra"})
1125 : checker.checkRewardAwareUnfold(this->env(), *data.propertyInfo, options, bounds, {
"rew",
"extra"});
1126 EXPECT_TRUE(result.completedExploration);
1127 EXPECT_LE(
storm::utility::abs(result.value - expected), this->template modelcheckingPrecision<BeliefMDPValueType>());
1131TYPED_TEST(BeliefBasedModelCheckerTest, reward_bounded_simple_early_frontier_uses_cutoff) {
1133 typedef typename TestFixture::POMDPValueType POMDPValueType;
1134 typedef typename TestFixture::BeliefValueType BeliefValueType;
1135 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1137 auto check = [
this](std::string
const& formula, std::string
const& frontierValue, std::string
const& completeValue) {
1138 SCOPED_TRACE(formula);
1139 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple_unit_rewards.prism", formula,
"slippery=0");
1151 std::vector<std::string> rewardModelNames;
1152 for (
auto const& rewardBound : data.propertyInfo->rewardBounds) {
1153 rewardModelNames.push_back(rewardBound.rewardModelName);
1155 for (
bool const discretize : {
false,
true}) {
1156 SCOPED_TRACE(discretize ?
"discretize" :
"unfold");
1159 checker.checkRewardAwareDiscretize(this->env(), *data.propertyInfo, options, 10,
false, precomputedBeliefBounds, rewardModelNames),
1160 storm::exceptions::NotSupportedException);
1164 discretize ? checker.checkRewardAwareDiscretize(this->env(), *data.propertyInfo, options, 10,
false, precomputedBeliefBounds, rewardModelNames)
1165 : checker.checkRewardAwareUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds, rewardModelNames);
1166 EXPECT_EQ(result.completedExploration, discretize);
1168 EXPECT_GT(result.statistics.exploredBeliefs, 1);
1170 EXPECT_EQ(result.statistics.exploredBeliefs, 1);
1171 EXPECT_GT(result.statistics.discoveredBeliefs, result.statistics.exploredBeliefs);
1173 auto const expected = this->
template parseNumber<BeliefMDPValueType>(discretize ? completeValue : frontierValue);
1174 EXPECT_LE(
storm::utility::abs(result.value - expected), this->template modelcheckingPrecision<BeliefMDPValueType>());
1179 check(
"Pmin=? [ true Urew{\"rew\"}<=3 \"goal\" ]",
"1",
"3/10");
1180 check(
"Pmax=? [ true Urew{\"rew\"}<=3 \"goal\" ]",
"0",
"7/10");
1182 check(
"Pmin=? [ true Urew{\"rew\"}<=0 \"goal\" ]",
"0",
"0");
1183 check(
"Pmax=? [ true Urew{\"rew\"}<=0 \"goal\" ]",
"0",
"0");
1186TYPED_TEST(BeliefBasedModelCheckerTest, reward_bounded_hidden_transition_costs) {
1187 using POMDPValueType =
typename TestFixture::POMDPValueType;
1188 using BeliefValueType =
typename TestFixture::BeliefValueType;
1189 using BeliefMDPValueType =
typename TestFixture::BeliefMDPValueType;
1192 auto check = [
this](std::string
const& formula, std::string
const& expectedValue,
bool stopAtTargetFrontier, std::string
const& completedValue =
"") {
1193 SCOPED_TRACE(formula);
1194 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/hidden_transition_rewards.prism", formula);
1203 if (stopAtTargetFrontier) {
1208 for (
bool const discretize : {
false,
true}) {
1209 SCOPED_TRACE(discretize ?
"discretize" :
"unfold");
1210 if (stopAtTargetFrontier && discretize) {
1211 STORM_SILENT_EXPECT_THROW(checker.checkRewardAwareDiscretize(this->env(), *data.propertyInfo, options, 2,
false, bounds, {
"cost"}),
1212 storm::exceptions::NotSupportedException);
1215 auto const result = discretize ? checker.checkRewardAwareDiscretize(this->env(), *data.propertyInfo, options, 2,
false, bounds, {
"cost"})
1216 : checker.checkRewardAwareUnfold(this->env(), *data.propertyInfo, options, bounds, {
"cost"});
1217 EXPECT_EQ(result.completedExploration, discretize || !stopAtTargetFrontier);
1218 if (stopAtTargetFrontier && !discretize) {
1219 EXPECT_EQ(result.statistics.exploredBeliefs, 2);
1220 EXPECT_GT(result.statistics.discoveredBeliefs, result.statistics.exploredBeliefs);
1222 auto const expected = this->
template parseNumber<BeliefMDPValueType>(discretize && !completedValue.empty() ? completedValue : expectedValue);
1223 EXPECT_LE(
storm::utility::abs(result.value - expected), this->template modelcheckingPrecision<BeliefMDPValueType>())
1224 <<
"actual: " << result.value <<
", expected: " << expected;
1229 check(
"Pmin=? [ true Urew{\"cost\"}<=1 \"goal\" ]",
"1/2",
false);
1230 check(
"Pmax=? [ true Urew{\"cost\"}<=1 \"goal\" ]",
"1/2",
false);
1231 check(
"Pmin=? [ true Urew{\"cost\"}<=2 \"goal\" ]",
"1",
false);
1232 check(
"Pmax=? [ true Urew{\"cost\"}<=2 \"goal\" ]",
"1",
false);
1234 check(
"Pmin=? [ true Urew{\"cost\"}>=2 \"goal\" ]",
"1",
false);
1235 check(
"Pmax=? [ true Urew{\"cost\"}>=2 \"goal\" ]",
"1",
false);
1237 check(
"Pmin=? [ true Urew{\"cost\"}<=1 \"goal\" ]",
"1/2",
true);
1238 check(
"Pmax=? [ true Urew{\"cost\"}<=1 \"goal\" ]",
"1/2",
true);
1240 check(
"Pmin=? [ true Urew{\"cost\"}>=2 \"goal\" ]",
"1",
true);
1241 check(
"Pmax=? [ true Urew{\"cost\"}>=2 \"goal\" ]",
"1/2",
true,
"1");
1244TYPED_TEST(BeliefBasedModelCheckerTest, reward_bounded_min_lower_bound_frontier_collects_reward) {
1245 using POMDPValueType =
typename TestFixture::POMDPValueType;
1246 using BeliefMDPValueType =
typename TestFixture::BeliefMDPValueType;
1249 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/hidden_transition_rewards.prism",
"Pmin=? [ true Urew{\"cost\"}>=2 \"goal\" ]");
1250 auto extraRewardModel = data.model->getRewardModel(
"cost");
1251 data.model->addRewardModel(
"extra", extraRewardModel);
1258 std::vector<storm::pomdp::beliefs::PropertyInformation> properties{*data.propertyInfo};
1259 auto strictProperty = *data.propertyInfo;
1260 strictProperty.rewardBounds.front().lowerBound =
storm::logic::TimeBound(
true, data.propertyInfo->rewardBounds.front().lowerBound->getBound());
1261 properties.push_back(strictProperty);
1262 auto zeroBoundData = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/hidden_transition_rewards.prism",
"Pmin=? [ true Urew{\"cost\"}>=0 \"goal\" ]");
1263 properties.push_back(*zeroBoundData.propertyInfo);
1264 auto multidimensionalProperty = *data.propertyInfo;
1265 auto extraLowerBound = strictProperty.rewardBounds.front();
1266 extraLowerBound.rewardModelName =
"extra";
1267 multidimensionalProperty.rewardBounds.push_back(extraLowerBound);
1268 properties.push_back(multidimensionalProperty);
1272 for (uint64_t
const sizeLimit : {1, 2}) {
1273 SCOPED_TRACE(sizeLimit);
1276 for (std::size_t i = 0;
i < properties.size(); ++
i) {
1278 std::vector<std::string> rewardModelNames;
1279 for (
auto const& rewardBound : properties[i].rewardBounds) {
1280 rewardModelNames.push_back(rewardBound.rewardModelName);
1282 auto const result = checker.checkRewardAwareUnfold(this->env(), properties[i], options, bounds, rewardModelNames);
1283 EXPECT_FALSE(result.completedExploration);
1284 EXPECT_EQ(result.statistics.exploredBeliefs, sizeLimit);
1286 this->template modelcheckingPrecision<BeliefMDPValueType>());
1291 auto upperBoundData = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/hidden_transition_rewards.prism",
"Pmin=? [ true Urew{\"cost\"}<=1 \"goal\" ]");
1292 auto upperOnlyBound = upperBoundData.propertyInfo->rewardBounds.front();
1293 upperOnlyBound.rewardModelName =
"extra";
1294 auto mixedProperty = strictProperty;
1295 mixedProperty.rewardBounds.insert(mixedProperty.rewardBounds.begin(), upperOnlyBound);
1297 auto const mixedResult = checker.checkRewardAwareUnfold(this->env(), mixedProperty, options, bounds, {
"extra",
"cost"});
1298 EXPECT_FALSE(mixedResult.completedExploration);
1299 auto const mixedExpected = this->
template parseNumber<BeliefMDPValueType>(
"1/2");
1300 EXPECT_LE(
storm::utility::abs(mixedResult.value - mixedExpected), this->template modelcheckingPrecision<BeliefMDPValueType>());
1303 for (
auto const criterion :
1305 SCOPED_TRACE(criterion);
1314 auto const result = checker.checkRewardAwareUnfold(this->env(), *data.propertyInfo, options, bounds, {
"cost"});
1315 EXPECT_TRUE(result.completedExploration);
1320TYPED_TEST(BeliefBasedModelCheckerTest, reward_bounded_min_rejects_two_sided_dimensions) {
1321 using POMDPValueType =
typename TestFixture::POMDPValueType;
1322 using BeliefMDPValueType =
typename TestFixture::BeliefMDPValueType;
1325 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/hidden_transition_rewards.prism",
"Pmin=? [ true Urew{\"cost\"}>=2 \"goal\" ]");
1326 auto extraRewardModel = data.model->getRewardModel(
"cost");
1327 data.model->addRewardModel(
"extra", extraRewardModel);
1330 auto intervalProperty = *data.propertyInfo;
1331 intervalProperty.rewardBounds.front().upperBound = intervalProperty.rewardBounds.front().lowerBound;
1332 auto zeroBoundData = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/hidden_transition_rewards.prism",
"Pmin=? [ true Urew{\"cost\"}>=0 \"goal\" ]");
1333 auto zeroIntervalProperty = intervalProperty;
1334 zeroIntervalProperty.rewardBounds.front().lowerBound = zeroBoundData.propertyInfo->rewardBounds.front().lowerBound;
1335 auto multidimensionalProperty = *data.propertyInfo;
1336 auto extraIntervalBound = intervalProperty.rewardBounds.front();
1337 extraIntervalBound.rewardModelName =
"extra";
1338 multidimensionalProperty.rewardBounds.push_back(extraIntervalBound);
1343 for (
auto const& property : {intervalProperty, zeroIntervalProperty, multidimensionalProperty}) {
1344 std::vector<std::string> rewardModelNames;
1345 for (
auto const& rewardBound : property.rewardBounds) {
1346 rewardModelNames.push_back(rewardBound.rewardModelName);
1348 for (
bool const limited : {
false,
true}) {
1349 SCOPED_TRACE(limited);
1352 storm::exceptions::NotSupportedException);
1353 STORM_SILENT_EXPECT_THROW(checker.checkRewardAwareDiscretize(this->env(), property, options, 2,
false, bounds, rewardModelNames),
1354 storm::exceptions::NotSupportedException);
1359 intervalProperty.dir = storm::OptimizationDirection::Maximize;
1364 for (
bool const discretize : {
false,
true}) {
1365 SCOPED_TRACE(discretize);
1366 auto check = [&]() {
1369 checker.checkRewardAwareDiscretize(this->env(), intervalProperty, options, 2,
false, bounds, {
"cost"});
1371 checker.checkRewardAwareUnfold(this->env(), intervalProperty, options, bounds, {
"cost"});
1373 }
catch (storm::exceptions::NotSupportedException
const& exception) {
1374 EXPECT_NE(std::string(exception.what()).find(
"Bounded until formulas are only supported by this method"), std::string::npos);
1382#if defined STORM_HAVE_LP_SOLVER
1383TYPED_TEST(BeliefBasedModelCheckerTest, clip_simple_Pmax) {
1385 typedef typename TestFixture::POMDPValueType POMDPValueType;
1386 typedef typename TestFixture::BeliefValueType BeliefValueType;
1387 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1389 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Pmax=? [F \"goal\" ]",
"slippery=0");
1394 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1402 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
1403 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1405 auto expected = this->
template parseNumber<BeliefMDPValueType>(
"7/10");
1407 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
1408 overResultValue = overCheckResult.value;
1409 EXPECT_LE(overResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
1411 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1412 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1413 underResultValue = underCheckResult.value;
1414 EXPECT_LE(underResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
1416 <<
"Result [" << underResultValue <<
", " << overResultValue
1417 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
1420TYPED_TEST(BeliefBasedModelCheckerTest, clip_simple_Pmin) {
1422 typedef typename TestFixture::POMDPValueType POMDPValueType;
1423 typedef typename TestFixture::BeliefValueType BeliefValueType;
1424 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1426 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Pmin=? [F \"goal\" ]",
"slippery=0");
1431 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1439 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
1440 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1442 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"3/10");
1444 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
1445 overResultValue = overCheckResult.value;
1446 EXPECT_GE(overResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
1448 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1449 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1450 underResultValue = underCheckResult.value;
1451 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
1453 <<
"Result [" << overResultValue <<
", " << underResultValue
1454 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
1457TYPED_TEST(BeliefBasedModelCheckerTest, clip_simple_Pmin_early_clipping_is_sound) {
1459 typedef typename TestFixture::POMDPValueType POMDPValueType;
1460 typedef typename TestFixture::BeliefValueType BeliefValueType;
1461 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1463 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Pmin=? [F \"goal\" ]",
"slippery=0");
1468 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1476 auto underResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1477 auto expected = this->
template parseNumber<BeliefMDPValueType>(
"3/10");
1478 EXPECT_GE(underResult.value, expected - this->template modelcheckingPrecision<BeliefMDPValueType>());
1481TYPED_TEST(BeliefBasedModelCheckerTest, clip_simple_slippery_Pmax) {
1483 typedef typename TestFixture::POMDPValueType POMDPValueType;
1484 typedef typename TestFixture::BeliefValueType BeliefValueType;
1485 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1487 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Pmax=? [F \"goal\" ]",
"slippery=0.4");
1492 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1500 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1502 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"7/10");
1504 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1506 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1507 underResultValue = underCheckResult.value;
1508 EXPECT_LE(underResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
1511TYPED_TEST(BeliefBasedModelCheckerTest, clip_simple_slippery_Pmin) {
1513 typedef typename TestFixture::POMDPValueType POMDPValueType;
1514 typedef typename TestFixture::BeliefValueType BeliefValueType;
1515 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1517 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Pmin=? [F \"goal\" ]",
"slippery=0.4");
1522 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1529 typename TestFixture::ExtendedBeliefMDPValueType overResultValue;
1530 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1532 POMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"3/10");
1533 auto overCheckResult = checker.checkDiscretize(this->env(), *data.propertyInfo, options, this->overApproxResolution(),
true, precomputedBeliefBounds);
1534 overResultValue = overCheckResult.value;
1536 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1537 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1538 underResultValue = underCheckResult.value;
1539 if (this->isExact()) {
1543 EXPECT_GE(underResultValue, expected - approxPrecision);
1544 EXPECT_LE(overResultValue, expected + approxPrecision);
1546 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
1547 EXPECT_LE(overResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
1550 <<
"Result [" << underResultValue <<
", " << overResultValue
1551 <<
"] is not precise enough. If (only) this fails, the result bounds are still correct, but they might be unexpectedly imprecise.\n";
1554TYPED_TEST(BeliefBasedModelCheckerTest, clip_simple_Rmax) {
1556 typedef typename TestFixture::POMDPValueType POMDPValueType;
1557 typedef typename TestFixture::BeliefValueType BeliefValueType;
1558 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1560 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Rmax=? [F s>4 ]",
"slippery=0");
1565 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1566 precomputedBeliefBounds.
extremeBounds = preprocessChecker.getExtremeValueBound(this->env(), *data.formula);
1574 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1576 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"29/50");
1578 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1579 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1580 underResultValue = underCheckResult.value;
1581 EXPECT_LE(underResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
1584TYPED_TEST(BeliefBasedModelCheckerTest, clip_simple_Rmin) {
1586 typedef typename TestFixture::POMDPValueType POMDPValueType;
1587 typedef typename TestFixture::BeliefValueType BeliefValueType;
1588 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1590 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Rmin=? [F s>4 ]",
"slippery=0");
1595 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1596 precomputedBeliefBounds.
extremeBounds = preprocessChecker.getExtremeValueBound(this->env(), *data.formula);
1604 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1606 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"19/50");
1608 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1609 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1610 underResultValue = underCheckResult.value;
1611 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
1614TYPED_TEST(BeliefBasedModelCheckerTest, clip_simple_slippery_Rmax) {
1616 typedef typename TestFixture::POMDPValueType POMDPValueType;
1617 typedef typename TestFixture::BeliefValueType BeliefValueType;
1618 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1620 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Rmax=? [F s>4 ]",
"slippery=0.4");
1625 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1626 precomputedBeliefBounds.
extremeBounds = preprocessChecker.getExtremeValueBound(this->env(), *data.formula);
1634 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1636 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"29/30");
1638 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1639 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1640 underResultValue = underCheckResult.value;
1641 EXPECT_LE(underResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
1644TYPED_TEST(BeliefBasedModelCheckerTest, clip_simple_slippery_Rmin) {
1646 typedef typename TestFixture::POMDPValueType POMDPValueType;
1647 typedef typename TestFixture::BeliefValueType BeliefValueType;
1648 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1650 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/simple.prism",
"Rmin=? [F s>4 ]",
"slippery=0.4");
1655 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1656 precomputedBeliefBounds.
extremeBounds = preprocessChecker.getExtremeValueBound(this->env(), *data.formula);
1664 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1666 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"19/30");
1668 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1669 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1670 underResultValue = underCheckResult.value;
1671 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
1674TYPED_TEST(BeliefBasedModelCheckerTest, clip_maze2_Rmin) {
1676 typedef typename TestFixture::POMDPValueType POMDPValueType;
1677 typedef typename TestFixture::BeliefValueType BeliefValueType;
1678 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1680 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"Rmin=? [F \"goal\"]",
"sl=0");
1685 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1686 precomputedBeliefBounds.
extremeBounds = preprocessChecker.getExtremeValueBound(this->env(), *data.formula);
1694 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1696 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"74/91");
1697 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1698 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1699 underResultValue = underCheckResult.value;
1700 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
1703TYPED_TEST(BeliefBasedModelCheckerTest, clip_maze2_Rmax) {
1705 typedef typename TestFixture::POMDPValueType POMDPValueType;
1706 typedef typename TestFixture::BeliefValueType BeliefValueType;
1707 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1709 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"Rmax=? [F \"goal\"]",
"sl=0");
1714 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1715 precomputedBeliefBounds.
extremeBounds = preprocessChecker.getExtremeValueBound(this->env(), *data.formula);
1723 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1725 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1726 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1727 underResultValue = underCheckResult.value;
1731TYPED_TEST(BeliefBasedModelCheckerTest, clip_maze2_slippery_Rmin) {
1733 typedef typename TestFixture::POMDPValueType POMDPValueType;
1734 typedef typename TestFixture::BeliefValueType BeliefValueType;
1735 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1737 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"Rmin=? [F \"goal\"]",
"sl=0.075");
1742 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1743 precomputedBeliefBounds.
extremeBounds = preprocessChecker.getExtremeValueBound(this->env(), *data.formula);
1751 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1753 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"80/91");
1755 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1756 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1757 underResultValue = underCheckResult.value;
1758 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
1761TYPED_TEST(BeliefBasedModelCheckerTest, clip_maze2_slippery_Rmax) {
1763 typedef typename TestFixture::POMDPValueType POMDPValueType;
1764 typedef typename TestFixture::BeliefValueType BeliefValueType;
1765 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1767 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"Rmax=? [F \"goal\"]",
"sl=0.075");
1772 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1773 precomputedBeliefBounds.
extremeBounds = preprocessChecker.getExtremeValueBound(this->env(), *data.formula);
1781 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1783 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1784 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1785 underResultValue = underCheckResult.value;
1789TYPED_TEST(BeliefBasedModelCheckerTest, clip_refuel_Pmax) {
1791 typedef typename TestFixture::POMDPValueType POMDPValueType;
1792 typedef typename TestFixture::BeliefValueType BeliefValueType;
1793 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1795 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/refuel.prism",
"Pmax=?[\"notbad\" U \"goal\"]",
"N=4");
1800 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1808 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1810 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"38/155");
1812 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1813 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1814 underResultValue = underCheckResult.value;
1815 EXPECT_LE(underResultValue, expected + this->
template modelcheckingPrecision<BeliefMDPValueType>());
1818TYPED_TEST(BeliefBasedModelCheckerTest, clip_refuel_Pmin) {
1820 typedef typename TestFixture::POMDPValueType POMDPValueType;
1821 typedef typename TestFixture::BeliefValueType BeliefValueType;
1822 typedef typename TestFixture::BeliefMDPValueType BeliefMDPValueType;
1824 auto data = this->buildPrism(STORM_TEST_RESOURCES_DIR
"/pomdp/refuel.prism",
"Pmin=?[\"notbad\" U \"goal\"]",
"N=4");
1829 precomputedBeliefBounds.
preprocessingBounds = preprocessChecker.getValueBounds(this->env(), *data.formula);
1837 typename TestFixture::ExtendedBeliefMDPValueType underResultValue;
1839 BeliefMDPValueType expected = this->
template parseNumber<BeliefMDPValueType>(
"0");
1841 options.
maxExplorationSize = data.model->getNumberOfStates() * data.model->getMaxNrStatesWithSameObservation();
1842 auto underCheckResult = checker.checkUnfold(this->env(), *data.propertyInfo, options, precomputedBeliefBounds);
1843 underResultValue = underCheckResult.value;
1844 EXPECT_GE(underResultValue, expected - this->
template modelcheckingPrecision<BeliefMDPValueType>());
SolverEnvironment & solver()
void setPrecision(storm::RationalNumber value)
void setMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault=false)
Helper class that optionally holds a reference to an object of type T.
MinMaxSolverEnvironment & minMax()
void setForceSoundness(bool value)
void setForceExact(bool value)
This class represents a partially observable Markov decision process.
Builds and checks a finite belief MDP approximation of a POMDP.
Class to perform belief exploration.
Represents a belief of a Pomdp, i.e.
Abstracts a given belief by splitting it into sub-beliefs based on the (state-action) reward of the P...
Program preprocess(std::map< storm::expressions::Variable, storm::expressions::Expression > const &constantDefinitions) const
Preprocesses the program by defining the given constant definitions, substituting constants and formu...
#define STORM_LOG_THROW(cond, exception, message)
std::vector< storm::jani::Property > parsePropertiesForPrismProgram(std::string const &inputString, storm::prism::Program const &program, boost::optional< std::set< std::string > > const &propertyFilter)
storm::prism::Program parseProgram(std::string const &filename, bool prismCompatibility, bool simplify)
std::shared_ptr< storm::models::sparse::Model< ValueType > > buildSparseModel(storm::storage::SymbolicModelDescription const &model, storm::builder::BuilderOptions const &options, typename storm::builder::ExplicitModelBuilder< ValueType >::Options const &explorationOptions=typename storm::builder::ExplicitModelBuilder< ValueType >::Options())
SFTBDDChecker::ValueType ValueType
helper::MDPSparseModelCheckingHelperReturnType< ValueType > check(Environment const &env, SparseModelType const &model, CheckTask< storm::logic::MultiObjectiveFormula, ValueType > const &checkTask, CheckFormulaCallback const &formulaChecker)
check a lexicographic LTL-formula
NumberType parseNumber(std::string const &value)
Parse number from string.
FormulaInformation getFormulaInformation(PomdpType const &pomdp, storm::logic::ProbabilityOperatorFormula const &formula)
constexpr NoAbstractionType NoAbstraction
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
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 getReachableStates(storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::BitVector const &initialStates, storm::storage::BitVector const &constraintStates, storm::storage::BitVector const &targetStates, bool useStepBound, uint_fast64_t maximalSteps, boost::optional< storm::storage::BitVector > const &choiceFilter)
Performs a forward depth-first search through the underlying graph structure to identify the states t...
ExtendedValueType< ValueType > positiveInfinity()
ValueType abs(ValueType const &number)
std::conditional_t< storm::NumberTraits< ValueType >::HasInfinity, ValueType, ExtendedNumber< ValueType > > ExtendedValueType
The type to use for values that may be infinite.
TargetType convertNumber(SourceType const &number)
constexpr NullRefType NullRef
TYPED_TEST(GraphTestAR, SymbolicProb01StochasticGameDieSmall)
TYPED_TEST_SUITE(GraphTestAR, TestingTypes,)
::testing::Types< Cudd, Sylvan > TestingTypes
#define STORM_SILENT_EXPECT_THROW(statement, expected_exception)
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
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
std::unordered_map< std::string, RewardModelType > rewardModels
storm::storage::SparseMatrix< ValueType > transitionMatrix
std::optional< storm::storage::sparse::Valuations > observationValuations
std::optional< storm::models::sparse::ChoiceLabeling > choiceLabeling
storm::models::sparse::StateLabeling stateLabeling
std::optional< std::vector< uint32_t > > observabilityClasses