7#include "storm-config.h"
26class UmbRoundTripTest :
public ::testing::Test {
28 std::filesystem::path umbFile;
29 void removeUmbFile() {
30 if (!umbFile.empty() && std::filesystem::exists(umbFile)) {
32 std::filesystem::remove(umbFile);
33 ASSERT_EQ(ec.value(), 0) <<
"Unable to remove temporary file " << umbFile <<
" for UMB round trip test: " << ec.message();
37 void setUpUmbFileName() {
39 auto tmp = std::filesystem::temp_directory_path(ec);
40 ASSERT_EQ(ec.value(), 0) <<
"Unable to get temporary directory for UMB round trip test: " << ec.message();
41 std::random_device rd;
43 umbFile = tmp / std::filesystem::path(
"storm_umb_round_trip_test_" + std::to_string(rd()) +
".umb");
44 }
while (std::filesystem::exists(umbFile));
47 template<
typename ValueType>
48 void run(std::filesystem::path
const& prismfile, std::string
const& constants =
"", storm::umb::ExportOptions
const& exportOptions = {}) {
51 storm::umb::ImportOptions importOptions;
52 importOptions.
buildChoiceLabeling = exportOptions.allowChoiceLabelingAsActions || exportOptions.allowChoiceOriginsAsActions;
64 auto builder = storm::builder::ExplicitModelBuilder<ValueType>(program, generatorOptions);
65 auto model = builder.build();
67 auto assertEqualModel = [&model](
auto const& otherModelPtr) {
68 ASSERT_TRUE(otherModelPtr) <<
"No model.";
69 EXPECT_EQ(model->getType(), otherModelPtr->getType());
70 EXPECT_EQ(model->getNumberOfStates(), otherModelPtr->getNumberOfStates());
71 EXPECT_EQ(model->getNumberOfChoices(), otherModelPtr->getNumberOfChoices());
72 EXPECT_EQ(model->getNumberOfTransitions(), otherModelPtr->getNumberOfTransitions());
75 EXPECT_EQ(model->getTransitionMatrix(), otherModelPtr->getTransitionMatrix());
77 EXPECT_EQ(model->getStateLabeling(), otherModelPtr->getStateLabeling());
78 if (model->isNondeterministicModel() && model->hasChoiceLabeling()) {
80 EXPECT_EQ(model->getChoiceLabeling(), otherModelPtr->getChoiceLabeling());
82 EXPECT_EQ(model->getNumberOfRewardModels(), otherModelPtr->getNumberOfRewardModels());
83 for (
auto const& [name, rewardModel] : model->getRewardModels()) {
84 ASSERT_TRUE(otherModelPtr->hasRewardModel(name) || model->hasUniqueRewardModel()) <<
"Other model does not have reward model '" << name <<
"'.";
85 auto const& otherRewardModel = model->hasUniqueRewardModel() ? otherModelPtr->getUniqueRewardModel() : otherModelPtr->getRewardModel(name);
86 if (rewardModel.hasStateRewards()) {
87 ASSERT_TRUE(otherRewardModel.hasStateRewards());
88 EXPECT_EQ(rewardModel.getStateRewardVector(), otherRewardModel.getStateRewardVector());
90 if (rewardModel.hasStateActionRewards()) {
91 ASSERT_TRUE(otherRewardModel.hasStateActionRewards());
92 EXPECT_EQ(rewardModel.getStateActionRewardVector(), otherRewardModel.getStateActionRewardVector());
94 if (rewardModel.hasTransitionRewards()) {
95 ASSERT_TRUE(otherRewardModel.hasTransitionRewards());
96 EXPECT_EQ(rewardModel.getTransitionRewardMatrix(), otherRewardModel.getTransitionRewardMatrix());
99 auto assertEqualValuations = [](
auto const& v,
auto const& other_v) {
100 ASSERT_EQ(v.size(), other_v.size());
101 EXPECT_EQ(0, v.numStrings());
102 EXPECT_EQ(0, other_v.numStrings());
103 ASSERT_EQ(1, v.numClasses());
104 ASSERT_EQ(1, other_v.numClasses());
105 ASSERT_EQ(v.getClassDescription().sizeInBits(), other_v.getClassDescription().sizeInBits());
106 storm::umb::UmbModel::Valuation data = v.getRawUmbData();
107 storm::umb::UmbModel::Valuation other_data = other_v.getRawUmbData();
113 ASSERT_TRUE(model->hasStateValuations());
114 ASSERT_TRUE(otherModelPtr->hasStateValuations());
115 assertEqualValuations(model->getStateValuations().getStorage(), otherModelPtr->getStateValuations().getStorage());
117 if (model->isPartiallyObservable()) {
119 auto pomdp = model->template as<storm::models::sparse::Pomdp<ValueType>>();
120 auto otherPomdp = otherModelPtr->template as<storm::models::sparse::Pomdp<ValueType>>();
121 EXPECT_EQ(pomdp->getObservations(), otherPomdp->getObservations());
122 ASSERT_TRUE(pomdp->hasObservationValuations());
123 ASSERT_TRUE(otherPomdp->hasObservationValuations());
124 assertEqualValuations(pomdp->getObservationValuations().getStorage(), otherPomdp->getObservationValuations().getStorage());
130 umb1.encodeRationals();
131 std::stringstream validationErrors;
132 ASSERT_TRUE(umb1.validate(validationErrors)) << validationErrors.str();
133 validationErrors.clear();
135 assertEqualModel(model1);
140 ASSERT_TRUE(umb2.validate(validationErrors)) << validationErrors.str();
141 validationErrors.clear();
143 assertEqualModel(model2);
147 virtual void SetUp()
override {
149 GTEST_SKIP() <<
"Z3 not available.";
151#ifndef STORM_HAVE_LIBARCHIVE
152 GTEST_SKIP() <<
"LibArchive not available.";
156 virtual void TearDown()
override {
161TEST_F(UmbRoundTripTest, brp_dtmc) {
163 run<double>(STORM_TEST_RESOURCES_DIR
"/dtmc/brp-16-2.pm",
"", options);
164 run<storm::RationalNumber>(STORM_TEST_RESOURCES_DIR
"/dtmc/brp-16-2.pm",
"", options);
165 run<storm::Interval>(STORM_TEST_RESOURCES_DIR
"/dtmc/brp-16-2.pm",
"", options);
166 run<storm::RationalInterval>(STORM_TEST_RESOURCES_DIR
"/dtmc/brp-16-2.pm",
"", options);
168 run<double>(STORM_TEST_RESOURCES_DIR
"/dtmc/brp-16-2.pm",
"", options);
170 run<double>(STORM_TEST_RESOURCES_DIR
"/dtmc/brp-16-2.pm",
"", options);
172 run<double>(STORM_TEST_RESOURCES_DIR
"/dtmc/brp-16-2.pm",
"", options);
175TEST_F(UmbRoundTripTest, embedded_ctmc) {
177 run<double>(STORM_TEST_RESOURCES_DIR
"/ctmc/embedded2.sm",
"", options);
178 run<storm::RationalNumber>(STORM_TEST_RESOURCES_DIR
"/ma/polling.ma",
"N=3,Q=3", options);
179 run<storm::Interval>(STORM_TEST_RESOURCES_DIR
"/ma/polling.ma",
"N=3,Q=3", options);
180 run<storm::RationalInterval>(STORM_TEST_RESOURCES_DIR
"/ma/polling.ma",
"N=3,Q=3", options);
183TEST_F(UmbRoundTripTest, firewire_mdp) {
185 run<double>(STORM_TEST_RESOURCES_DIR
"/mdp/firewire3-0.5.nm",
"", options);
186 run<storm::RationalNumber>(STORM_TEST_RESOURCES_DIR
"/mdp/firewire3-0.5.nm",
"", options);
187 run<storm::Interval>(STORM_TEST_RESOURCES_DIR
"/mdp/firewire3-0.5.nm",
"", options);
188 run<storm::RationalInterval>(STORM_TEST_RESOURCES_DIR
"/mdp/firewire3-0.5.nm",
"", options);
191 run<double>(STORM_TEST_RESOURCES_DIR
"/mdp/firewire3-0.5.nm",
"", options);
194TEST_F(UmbRoundTripTest, polling_ma) {
196 run<double>(STORM_TEST_RESOURCES_DIR
"/ma/polling.ma",
"N=3,Q=3", options);
197 run<storm::RationalNumber>(STORM_TEST_RESOURCES_DIR
"/ma/polling.ma",
"N=3,Q=3", options);
198 run<storm::Interval>(STORM_TEST_RESOURCES_DIR
"/ma/polling.ma",
"N=3,Q=3", options);
199 run<storm::RationalInterval>(STORM_TEST_RESOURCES_DIR
"/ma/polling.ma",
"N=3,Q=3", options);
202TEST_F(UmbRoundTripTest, robot_imdp) {
204 run<storm::Interval>(STORM_TEST_RESOURCES_DIR
"/imdp/robot.prism",
"delta=0.5", options);
205 run<storm::RationalInterval>(STORM_TEST_RESOURCES_DIR
"/imdp/robot.prism",
"delta=0.5", options);
208TEST_F(UmbRoundTripTest, maze_pomdp) {
210 run<double>(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"sl=0.5", options);
211 run<storm::RationalNumber>(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"sl=0.5", options);
212 run<storm::Interval>(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"sl=0.5", options);
213 run<storm::RationalInterval>(STORM_TEST_RESOURCES_DIR
"/pomdp/maze2.prism",
"sl=0.5", options);
218TEST(UmbTest, RationalEncoding) {
224 std::vector<storm::RationalNumber> values(17);
232 values[6] = int64max / uint64max;
233 values[7] = int64min / uint64max;
235 auto const simpleRationals = std::span<storm::RationalNumber>(values.data(), 8);
240 ASSERT_EQ(simpleRationals.size(), decoded1.size());
241 for (
size_t i = 0; i < simpleRationals.size(); ++i) {
242 EXPECT_EQ(simpleRationals[i], decoded1[i]) <<
" at index " << i;
246 values[8] = int64max + one;
247 values[9] = one / (uint64max + one);
248 values[10] = int64min - one;
249 values[11] = one / (int64min - one);
250 values[12] = (int64min - one) / (uint64max + one);
252 "949667607787274453086419753000949667607787274453086419753000949667607787274453086419753000949667607787274453086419753000949667607787274453086419753000"
253 "9496676077872744530864197530009496676077872744530864197530009496676077872744530864197530/"
254 "780116505469339517040847240228739241622101546262265311616467711470010820006007800398204693387501962318501358930877102188539546463329577703105788853954"
255 "134811616465520508472358467546262155762385699576193087775947700108638258539546825539241654967");
256 values[14] = one / values[13];
257 values[15] = -values[13];
258 values[16] = -values[14];
265 ASSERT_EQ(values.size(), decoded2.size());
266 for (
size_t i = 0; i < values.size(); ++i) {
267 EXPECT_EQ(values[i], decoded2[i]) <<
" at index " << i;
TEST_F(AssumptionCheckerTest, Brp_no_bisimulation)
TEST(UmbTest, RationalEncoding)
BuilderOptions & setBuildAllLabels(bool newValue=true)
Should all reward models be built?
BuilderOptions & setBuildChoiceLabels(bool newValue=true)
Should the choice labels be built?
BuilderOptions & setBuildAllRewardModels(bool newValue=true)
Should all reward models be built?
BuilderOptions & setBuildChoiceOrigins(bool newValue=true)
Should the origins the different choices be built?
BuilderOptions & setBuildStateValuations(bool newValue=true)
Should the state valuation mapping be built?
BuilderOptions & setBuildObservationValuations(bool newValue=true)
Should a observation valuation mapping be built?
static storm::prism::Program parse(std::string const &filename, bool prismCompatability=false)
Parses the given file into the PRISM storage classes assuming it complies with the PRISM syntax.
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...
static uint64_t getMinimalRationalSize(InputRange &&input, bool multiplesOf64)
static std::vector< uint64_t > createUint64FromRationalRange(InputRange &&input, uint64_t const numberSize)
static auto uint64ToRationalRangeView(InputRange &&input, uint64_t const numberSize)
storm::builder::BuilderOptions NextStateGeneratorOptions
storm::umb::UmbModel importUmb(std::filesystem::path const &umbLocation, ImportOptions const &options)
void toArchive(storm::umb::UmbModel const &umbModel, std::filesystem::path const &archivePath, ExportOptions const &options)
std::shared_ptr< storm::models::sparse::Model< ValueType > > sparseModelFromUmb(storm::umb::UmbModel const &umbModel, ImportOptions const &options)
Constructs a sparse model from the given UMB model.
storm::umb::UmbModel sparseModelToUmb(storm::models::sparse::Model< ValueType > const &model, ExportOptions const &options)
TargetType convertNumber(SourceType const &number)
bool allowChoiceLabelingAsActions
Whether export of choice origins is enabled.
bool allowChoiceOriginsAsActions
Whether export of choice origins is enabled.
storm::io::CompressionMode compression
The type of compression used for the exported UMB model.
bool buildChoiceLabeling
Controls building of choice labelings.
TO1< uint32_t > valuationToClass