Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
model-handling.h
Go to the documentation of this file.
1#pragma once
2
3#include <filesystem>
4#include <type_traits>
5
6#include "storm/api/storm.h"
7
8#include "AutomaticSettings.h"
16#include "storm/io/file.h"
35#include "storm/storage/Qvbs.h"
46
47namespace storm {
48namespace cli {
49
51 // The symbolic model description.
52 boost::optional<storm::storage::SymbolicModelDescription> model;
53
54 // The original properties to check.
55 std::vector<storm::jani::Property> properties;
56
57 // The preprocessed properties to check (in case they needed amendment).
58 boost::optional<std::vector<storm::jani::Property>> preprocessedProperties;
59};
60
62 auto buildSettings = storm::settings::getModule<storm::settings::modules::BuildSettings>();
63 if (ioSettings.isPrismOrJaniInputSet()) {
64 storm::utility::Stopwatch modelParsingWatch(true);
65 if (ioSettings.isPrismInputSet()) {
66 input.model =
67 storm::api::parseProgram(ioSettings.getPrismInputFilename(), buildSettings.isPrismCompatibilityEnabled(), !buildSettings.isNoSimplifySet());
68 } else {
69 boost::optional<std::vector<std::string>> propertyFilter;
70 if (ioSettings.isJaniPropertiesSet()) {
71 if (ioSettings.areJaniPropertiesSelected()) {
72 propertyFilter = ioSettings.getSelectedJaniProperties();
73 } else {
74 propertyFilter = boost::none;
75 }
76 } else {
77 propertyFilter = std::vector<std::string>();
78 }
79 auto janiInput = storm::api::parseJaniModel(ioSettings.getJaniInputFilename(), propertyFilter);
80 input.model = std::move(janiInput.first);
81 if (ioSettings.isJaniPropertiesSet()) {
82 input.properties = std::move(janiInput.second);
83 }
84 }
85 modelParsingWatch.stop();
86 STORM_PRINT("Time for model input parsing: " << modelParsingWatch << ".\n\n");
87 }
88}
89
91 boost::optional<std::set<std::string>> const& propertyFilter) {
92 if (ioSettings.isPropertySet()) {
93 std::vector<storm::jani::Property> newProperties;
94 if (input.model) {
95 newProperties = storm::api::parsePropertiesForSymbolicModelDescription(ioSettings.getProperty(), input.model.get(), propertyFilter);
96 } else {
97 newProperties = storm::api::parseProperties(ioSettings.getProperty(), propertyFilter);
98 }
99
100 input.properties.insert(input.properties.end(), newProperties.begin(), newProperties.end());
101 }
102}
103
105 // Parse the model input
106 SymbolicInput input;
107 storm::storage::QvbsBenchmark benchmark(ioSettings.getQvbsModelName());
108 STORM_PRINT_AND_LOG(benchmark.getInfo(ioSettings.getQvbsInstanceIndex(), ioSettings.getQvbsPropertyFilter()));
109 storm::utility::Stopwatch modelParsingWatch(true);
110 auto janiInput = storm::api::parseJaniModel(benchmark.getJaniFile(ioSettings.getQvbsInstanceIndex()), ioSettings.getQvbsPropertyFilter());
111 input.model = std::move(janiInput.first);
112 input.properties = std::move(janiInput.second);
113 modelParsingWatch.stop();
114 STORM_PRINT("Time for model input parsing: " << modelParsingWatch << ".\n\n");
115
116 // Parse additional properties
117 boost::optional<std::set<std::string>> propertyFilter = storm::api::parsePropertyFilter(ioSettings.getPropertyFilter());
118 parseProperties(ioSettings, input, propertyFilter);
119
120 // Substitute constant definitions
121 auto constantDefinitions = input.model.get().parseConstantDefinitions(benchmark.getConstantDefinition(ioSettings.getQvbsInstanceIndex()));
122 input.model = input.model.get().preprocess(constantDefinitions);
123 if (!input.properties.empty()) {
124 input.properties = storm::api::substituteConstantsInProperties(input.properties, constantDefinitions);
125 }
126
127 return input;
128}
129
131 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
132 if (ioSettings.isQvbsInputSet()) {
133 return parseSymbolicInputQvbs(ioSettings);
134 } else {
135 // Parse the property filter, if any is given.
136 boost::optional<std::set<std::string>> propertyFilter = storm::api::parsePropertyFilter(ioSettings.getPropertyFilter());
137
138 SymbolicInput input;
139 parseSymbolicModelDescription(ioSettings, input);
140 parseProperties(ioSettings, input, propertyFilter);
141 return input;
142 }
143}
144
146 // The engine to use
148
149 // If set, bisimulation will be applied.
151
152 // If set, a transformation to Jani will be enforced
154
155 // Which data type is to be used for numbers ...
157 ValueType buildValueType; // ... during model building
158 ValueType verificationValueType; // ... during model verification
159
160 // The Dd library to be used
162
163 // The environment used during model checking
165
166 // A flag which is set to true, if the settings were detected to be compatible.
167 // If this is false, it could be that the query can not be handled.
169};
170
172 auto hints = storm::settings::getModule<storm::settings::modules::HintSettings>();
173
174 STORM_LOG_THROW(input.model.is_initialized(), storm::exceptions::InvalidArgumentException, "Automatic engine requires a JANI input model.");
175 STORM_LOG_THROW(input.model->isJaniModel(), storm::exceptions::InvalidArgumentException, "Automatic engine requires a JANI input model.");
176 std::vector<storm::jani::Property> const& properties =
177 input.preprocessedProperties.is_initialized() ? input.preprocessedProperties.get() : input.properties;
178 STORM_LOG_THROW(!properties.empty(), storm::exceptions::InvalidArgumentException, "Automatic engine requires a property.");
179 STORM_LOG_WARN_COND(properties.size() == 1,
180 "Automatic engine does not support decisions based on multiple properties. Only the first property will be considered.");
181
183 if (hints.isNumberStatesSet()) {
184 as.predict(input.model->asJaniModel(), properties.front(), hints.getNumberStates());
185 } else {
186 as.predict(input.model->asJaniModel(), properties.front());
187 }
188
189 mpi.engine = as.getEngine();
190 if (as.enableBisimulation()) {
191 mpi.applyBisimulation = true;
192 }
195 }
196 STORM_PRINT_AND_LOG("Automatic engine picked the following settings: \n"
197 << "\tengine=" << mpi.engine << std::boolalpha << "\t bisimulation=" << mpi.applyBisimulation
198 << "\t exact=" << (mpi.verificationValueType != ModelProcessingInformation::ValueType::FinitePrecision) << std::noboolalpha << '\n');
199}
200
207 std::shared_ptr<SymbolicInput> const& transformedJaniInput = nullptr) {
209 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
210 auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>();
211 auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>();
212 auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>();
213
214 // Set the engine.
215 mpi.engine = coreSettings.getEngine();
216
217 // Set whether bisimulation is to be used.
218 mpi.applyBisimulation = generalSettings.isBisimulationSet();
219
220 // Set the value type used for numeric values
221 if (generalSettings.isParametricSet()) {
223 } else if (generalSettings.isExactSet()) {
225 } else {
227 }
228 auto originalVerificationValueType = mpi.verificationValueType;
229
230 // Since the remaining settings could depend on the ones above, we need apply the automatic engine now.
231 bool useAutomatic = input.model.is_initialized() && mpi.engine == storm::utility::Engine::Automatic;
232 if (useAutomatic) {
233 if (input.model->isJaniModel()) {
234 // This can potentially overwrite the settings above, but will not overwrite settings that were explicitly set by the user (e.g. we will not disable
235 // bisimulation or disable exact arithmetic)
237 } else {
238 // Transform Prism to jani first
239 STORM_LOG_ASSERT(input.model->isPrismProgram(), "Unexpected type of input.");
240 SymbolicInput janiInput;
241 janiInput.properties = input.properties;
242 storm::prism::Program const& prog = input.model.get().asPrismProgram();
243 auto modelAndProperties = prog.toJani(input.preprocessedProperties.is_initialized() ? input.preprocessedProperties.get() : input.properties);
244 janiInput.model = modelAndProperties.first;
245 if (!modelAndProperties.second.empty()) {
246 janiInput.preprocessedProperties = std::move(modelAndProperties.second);
247 }
248 // This can potentially overwrite the settings above, but will not overwrite settings that were explicitly set by the user (e.g. we will not disable
249 // bisimulation or disable exact arithmetic)
251 if (transformedJaniInput) {
252 // We cache the transformation result.
253 *transformedJaniInput = std::move(janiInput);
254 }
255 }
256 }
257
258 // Check whether these settings are compatible with the provided input.
259 if (input.model) {
260 auto checkCompatibleSettings = [&mpi, &input] {
261 switch (mpi.verificationValueType) {
264 mpi.engine, input.preprocessedProperties.is_initialized() ? input.preprocessedProperties.get() : input.properties, input.model.get());
267 mpi.engine, input.preprocessedProperties.is_initialized() ? input.preprocessedProperties.get() : input.properties, input.model.get());
268 break;
271 mpi.engine, input.preprocessedProperties.is_initialized() ? input.preprocessedProperties.get() : input.properties, input.model.get());
272 }
273 return false;
274 };
275 mpi.isCompatible = checkCompatibleSettings();
276 if (!mpi.isCompatible) {
277 if (useAutomatic) {
279 STORM_LOG_WARN("The settings picked by the automatic engine (engine="
280 << mpi.engine << ", bisim=" << mpi.applyBisimulation << ", exact=" << useExact
281 << ") are incompatible with this model. Falling back to default settings.");
283 mpi.applyBisimulation = false;
284 mpi.verificationValueType = originalVerificationValueType;
285 // Retry check with new settings
286 mpi.isCompatible = checkCompatibleSettings();
287 }
288 }
289 } else {
290 // If there is no input model, nothing has to be done, actually
291 mpi.isCompatible = true;
292 }
293
294 // Set whether a transformation to jani is required or necessary
295 mpi.transformToJani = ioSettings.isPrismToJaniSet();
296 if (input.model) {
297 auto builderType = storm::utility::getBuilderType(mpi.engine);
298 bool transformToJaniForDdMA = (builderType == storm::builder::BuilderType::Dd) &&
299 (input.model->getModelType() == storm::storage::SymbolicModelDescription::ModelType::MA) && (!input.model->isJaniModel());
300 STORM_LOG_WARN_COND(mpi.transformToJani || !transformToJaniForDdMA,
301 "Dd-based model builder for Markov Automata is only available for JANI models, automatically converting the input model.");
302 mpi.transformToJani |= transformToJaniForDdMA;
303 }
304
305 // Set the Valuetype used during model building
307 if (bisimulationSettings.useExactArithmeticInDdBisimulation()) {
311 }
312 } else {
313 STORM_LOG_WARN("Requested using exact arithmetic in Dd bisimulation but no dd bisimulation is applied.");
314 }
315 }
316
317 // Set the Dd library
318 mpi.ddType = coreSettings.getDdLibraryType();
319 if (mpi.ddType == storm::dd::DdType::CUDD && coreSettings.isDdLibraryTypeSetFromDefaultValue()) {
322 STORM_LOG_INFO("Switching to DD library sylvan to allow for rational arithmetic.");
324 }
325 }
326 return mpi;
327}
328
329auto castAndApply(std::shared_ptr<storm::models::ModelBase> const& model, auto const& callback) {
330 STORM_LOG_ASSERT(model, "Tried to cast a model that does not exist.");
331
332 // Helper to actually perform the cast once value type and model representation type is known
333 auto castAndApplyImpl = [&model, &callback]<typename TargetModelType> {
334 auto res = model->template as<TargetModelType>();
335 STORM_LOG_ASSERT(res, "Casting model pointer failed unexpectedly.");
336 return callback(res);
337 };
338
339 // Helper to branch on type of model representation
340 auto castAndApplyVT = [&]<typename ValueType> {
341 if (model->isSparseModel()) {
342 return castAndApplyImpl.template operator()<storm::models::sparse::Model<ValueType>>();
343 } else {
344 auto ddType = model->getDdType();
345 STORM_LOG_ASSERT(model->isSymbolicModel() && ddType.has_value(), "Unexpected model representation");
346 if constexpr (storm::IsIntervalType<ValueType>) {
347 // Avoiding a couple of unnecessary template instantiations
348 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Symbolic interval models are currently not supported.");
349 } else {
350 using enum storm::dd::DdType;
351 if (*ddType == CUDD) {
352 if constexpr (std::is_same_v<ValueType, double>) {
353 return castAndApplyImpl.template operator()<storm::models::symbolic::Model<CUDD, ValueType>>();
354 }
355 }
356 STORM_LOG_ASSERT(*ddType == Sylvan, "Unexpected Dd type");
357 return castAndApplyImpl.template operator()<storm::models::symbolic::Model<Sylvan, ValueType>>();
358 }
359 }
360 };
361
362 // branch on type of value representation
363 if (model->supportsParameters()) {
364 return castAndApplyVT.template operator()<storm::RationalFunction>();
365 } else if (model->isExact()) {
366 return castAndApplyVT.template operator()<storm::RationalNumber>();
367 } else if (model->supportsUncertainty()) {
368 return castAndApplyVT.template operator()<storm::Interval>();
369 } else {
370 return castAndApplyVT.template operator()<double>();
371 }
372}
373
376 switch (vt) {
377 case FinitePrecision:
378 return callback.template operator()<double>();
379 case Exact:
380 return callback.template operator()<storm::RationalNumber>();
381 case Parametric:
382 return callback.template operator()<storm::RationalFunction>();
383 }
384 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unexpected value type.");
385}
386
388 using enum storm::dd::DdType;
390 switch (dd) {
391 case CUDD:
392 STORM_LOG_THROW(vt == FinitePrecision, storm::exceptions::UnexpectedException, "Unexpected value type for DD library Cudd.");
393 return callback.template operator()<CUDD, double>();
394 case Sylvan:
395 switch (vt) {
396 case FinitePrecision:
397 return callback.template operator()<Sylvan, double>();
398 case Exact:
399 return callback.template operator()<Sylvan, storm::RationalNumber>();
400 case Parametric:
401 return callback.template operator()<Sylvan, storm::RationalFunction>();
402 }
403 }
404 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unexpected DDType or value type.");
405}
406
407inline void ensureNoUndefinedPropertyConstants(std::vector<storm::jani::Property> const& properties) {
408 // Make sure there are no undefined constants remaining in any property.
409 for (auto const& property : properties) {
410 std::set<storm::expressions::Variable> usedUndefinedConstants = property.getUndefinedConstants();
411 if (!usedUndefinedConstants.empty()) {
412 std::vector<std::string> undefinedConstantsNames;
413 for (auto const& constant : usedUndefinedConstants) {
414 undefinedConstantsNames.emplace_back(constant.getName());
415 }
417 false, storm::exceptions::InvalidArgumentException,
418 "The property '" << property << " still refers to the undefined constants " << boost::algorithm::join(undefinedConstantsNames, ",") << ".");
419 }
420 }
421}
422
423inline std::pair<SymbolicInput, ModelProcessingInformation> preprocessSymbolicInput(SymbolicInput const& input) {
424 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
425
426 SymbolicInput output = input;
427
428 // Preprocess properties (if requested)
429 if (ioSettings.isPropertiesAsMultiSet()) {
430 STORM_LOG_THROW(!input.properties.empty(), storm::exceptions::InvalidArgumentException,
431 "Can not translate properties to multi-objective formula because no properties were specified.");
433 }
434
435 // Substitute constant definitions in symbolic input.
436 std::string constantDefinitionString = ioSettings.getConstantDefinitionString();
437 std::map<storm::expressions::Variable, storm::expressions::Expression> constantDefinitions;
438 if (output.model) {
439 constantDefinitions = output.model.get().parseConstantDefinitions(constantDefinitionString);
440 output.model = output.model.get().preprocess(constantDefinitions);
441 }
442 if (!output.properties.empty()) {
443 output.properties = storm::api::substituteConstantsInProperties(output.properties, constantDefinitions);
444 }
446 auto transformedJani = std::make_shared<SymbolicInput>();
447 ModelProcessingInformation mpi = getModelProcessingInformation(output, transformedJani);
448
449 // Check whether conversion for PRISM to JANI is requested or necessary.
450 if (output.model && output.model.get().isPrismProgram()) {
451 if (mpi.transformToJani) {
452 if (transformedJani->model) {
453 // Use the cached transformation if possible
454 output = std::move(*transformedJani);
455 } else {
456 storm::prism::Program const& model = output.model.get().asPrismProgram();
457 auto modelAndProperties = model.toJani(output.properties);
458
459 output.model = modelAndProperties.first;
460
461 if (!modelAndProperties.second.empty()) {
462 output.preprocessedProperties = std::move(modelAndProperties.second);
463 }
464 }
465 }
466 }
467
468 if (output.model && output.model.get().isJaniModel()) {
470 storm::api::simplifyJaniModel(output.model.get().asJaniModel(), output.properties, supportedFeatures);
471
472 const auto& buildSettings = storm::settings::getModule<storm::settings::modules::BuildSettings>();
473 if (buildSettings.isLocationEliminationSet()) {
474 auto locationHeuristic = buildSettings.getLocationEliminationLocationHeuristic();
475 auto edgesHeuristic = buildSettings.getLocationEliminationEdgesHeuristic();
476 output.model->setModel(storm::jani::JaniLocalEliminator::eliminateAutomatically(output.model.get().asJaniModel(), output.properties,
477 locationHeuristic, edgesHeuristic));
478 }
479 }
480
481 return {output, mpi};
482}
483
484inline void exportSymbolicInput(SymbolicInput const& input) {
485 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
486 if (input.model && input.model.get().isJaniModel()) {
487 storm::storage::SymbolicModelDescription const& model = input.model.get();
488 if (ioSettings.isExportJaniDotSet()) {
489 storm::api::exportJaniModelAsDot(model.asJaniModel(), ioSettings.getExportJaniDotFilename());
490 }
491 }
492}
493
494inline std::vector<std::shared_ptr<storm::logic::Formula const>> createFormulasToRespect(std::vector<storm::jani::Property> const& properties) {
495 std::vector<std::shared_ptr<storm::logic::Formula const>> result = storm::api::extractFormulasFromProperties(properties);
496
497 for (auto const& property : properties) {
498 if (!property.getFilter().getStatesFormula()->isInitialFormula()) {
499 result.push_back(property.getFilter().getStatesFormula());
500 }
501 }
502
503 return result;
504}
505
506template<storm::dd::DdType DdType, typename ValueType>
507std::shared_ptr<storm::models::ModelBase> buildModelDd(SymbolicInput const& input) {
508 if (DdType == storm::dd::DdType::Sylvan) {
509 auto numThreads = storm::settings::getModule<storm::settings::modules::SylvanSettings>().getNumberOfThreads();
510 STORM_PRINT_AND_LOG("Using Sylvan with " << numThreads << " parallel threads.\n");
511 }
512 auto buildSettings = storm::settings::getModule<storm::settings::modules::BuildSettings>();
513 return storm::api::buildSymbolicModel<DdType, ValueType>(input.model.get(), createFormulasToRespect(input.properties), buildSettings.isBuildFullModelSet(),
514 !buildSettings.isApplyNoMaximumProgressAssumptionSet());
515}
516
518 auto buildSettings = storm::settings::getModule<storm::settings::modules::BuildSettings>();
520 options.setBuildChoiceLabels(options.isBuildChoiceLabelsSet() || buildSettings.isBuildChoiceLabelsSet());
521 options.setBuildStateValuations(options.isBuildStateValuationsSet() || buildSettings.isBuildStateValuationsSet());
522 options.setBuildAllLabels(options.isBuildAllLabelsSet() || buildSettings.isBuildAllLabelsSet());
523 options.setBuildObservationValuations(options.isBuildObservationValuationsSet() || buildSettings.isBuildObservationValuationsSet());
524 bool buildChoiceOrigins = options.isBuildChoiceOriginsSet() || buildSettings.isBuildChoiceOriginsSet();
526 auto counterexampleGeneratorSettings = storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>();
527 if (counterexampleGeneratorSettings.isCounterexampleSet()) {
528 buildChoiceOrigins |= counterexampleGeneratorSettings.isMinimalCommandSetGenerationSet();
529 }
530 }
531 options.setBuildChoiceOrigins(buildChoiceOrigins);
532
533 if (buildSettings.isApplyNoMaximumProgressAssumptionSet()) {
535 }
536
537 if (buildSettings.isExplorationChecksSet()) {
538 options.setExplorationChecks();
539 }
540 options.setReservedBitsForUnboundedVariables(buildSettings.getBitsForUnboundedVariables());
541
542 options.setAddOutOfBoundsState(buildSettings.isBuildOutOfBoundsStateSet());
543 if (buildSettings.isBuildFullModelSet()) {
544 options.clearTerminalStates();
546 options.setBuildAllLabels(true);
547 options.setBuildAllRewardModels(true);
548 }
549
550 if (buildSettings.isAddOverlappingGuardsLabelSet()) {
551 options.setAddOverlappingGuardsLabel(true);
552 }
553
554 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
555 if (ioSettings.isComputeExpectedVisitingTimesSet() || ioSettings.isComputeSteadyStateDistributionSet()) {
556 options.clearTerminalStates();
557 }
558 return options;
559}
560
561template<typename ValueType>
562std::shared_ptr<storm::models::ModelBase> buildModelSparse(SymbolicInput const& input, storm::builder::BuilderOptions const& options) {
563 // Adapt the ValueType if it does not support intervals and the input is an interval model
564 if (!storm::IsIntervalType<ValueType> && input.model.is_initialized() && input.model->isPrismProgram() &&
565 input.model->asPrismProgram().hasIntervalUpdates()) {
566 STORM_LOG_THROW((std::is_same_v<ValueType, storm::IntervalBaseType<storm::Interval>>), storm::exceptions::NotSupportedException,
567 "Can not build interval model for the provided value type.");
568 return storm::api::buildSparseModel<storm::Interval>(input.model.get(), options);
569 } else {
570 return storm::api::buildSparseModel<ValueType>(input.model.get(), options);
571 }
572}
573
574template<typename ValueType>
575std::shared_ptr<storm::models::ModelBase> buildModelExplicit(storm::settings::modules::IOSettings const& ioSettings,
576 storm::settings::modules::BuildSettings const& buildSettings) {
577 std::shared_ptr<storm::models::ModelBase> result;
578 if (ioSettings.isExplicitSet()) {
579 result = storm::api::buildExplicitModel<ValueType>(
580 ioSettings.getTransitionFilename(), ioSettings.getLabelingFilename(),
581 ioSettings.isStateRewardsSet() ? boost::optional<std::string>(ioSettings.getStateRewardsFilename()) : boost::none,
582 ioSettings.isTransitionRewardsSet() ? boost::optional<std::string>(ioSettings.getTransitionRewardsFilename()) : boost::none,
583 ioSettings.isChoiceLabelingSet() ? boost::optional<std::string>(ioSettings.getChoiceLabelingFilename()) : boost::none);
584 } else if (ioSettings.isExplicitDRNSet()) {
586 options.buildChoiceLabeling = buildSettings.isBuildChoiceLabelsSet();
587 result = storm::api::buildExplicitDRNModel<ValueType>(ioSettings.getExplicitDRNFilename(), options);
588 } else {
589 STORM_LOG_THROW(ioSettings.isExplicitIMCASet(), storm::exceptions::InvalidSettingsException, "Unexpected explicit model input type.");
590 result = storm::api::buildExplicitIMCAModel<ValueType>(ioSettings.getExplicitIMCAFilename());
591 }
592 return result;
593}
594
595inline std::shared_ptr<storm::models::ModelBase> buildModel(SymbolicInput const& input, storm::settings::modules::IOSettings const& ioSettings,
596 ModelProcessingInformation const& mpi) {
597 storm::utility::Stopwatch modelBuildingWatch(true);
598
599 std::shared_ptr<storm::models::ModelBase> result;
600 if (input.model) {
601 auto builderType = storm::utility::getBuilderType(mpi.engine);
602 if (builderType == storm::builder::BuilderType::Dd) {
603 result = applyDdLibValueType(mpi.ddType, mpi.buildValueType, [&input]<storm::dd::DdType DD, typename VT>() { return buildModelDd<DD, VT>(input); });
604 } else if (builderType == storm::builder::BuilderType::Explicit) {
605 result = applyValueType(mpi.buildValueType, [&input]<typename VT>() {
606 auto options = createBuildOptionsSparseFromSettings(input);
607 return buildModelSparse<VT>(input, options);
608 });
609 }
610 } else if (ioSettings.isExplicitSet() || ioSettings.isExplicitDRNSet() || ioSettings.isExplicitIMCASet()) {
611 STORM_LOG_THROW(mpi.engine == storm::utility::Engine::Sparse, storm::exceptions::InvalidSettingsException,
612 "Can only use sparse engine with explicit input.");
613 result = applyValueType(mpi.buildValueType, [&ioSettings]<typename VT>() {
614 return buildModelExplicit<VT>(ioSettings, storm::settings::getModule<storm::settings::modules::BuildSettings>());
615 });
616 }
617
618 modelBuildingWatch.stop();
619 if (result) {
620 STORM_PRINT("Time for model construction: " << modelBuildingWatch << ".\n\n");
621 }
622
623 return result;
624}
625
626template<typename ValueType>
627std::shared_ptr<storm::models::sparse::Model<ValueType>> preprocessSparseMarkovAutomaton(
628 std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> const& model) {
629 auto transformationSettings = storm::settings::getModule<storm::settings::modules::TransformationSettings>();
630 auto debugSettings = storm::settings::getModule<storm::settings::modules::DebugSettings>();
631
632 std::shared_ptr<storm::models::sparse::Model<ValueType>> result = model;
633 model->close();
634 STORM_LOG_WARN_COND(!debugSettings.isAdditionalChecksSet() || !model->containsZenoCycle(),
635 "MA contains a Zeno cycle. Model checking results cannot be trusted.");
636
637 if (model->isConvertibleToCtmc()) {
638 STORM_LOG_WARN_COND(false, "MA is convertible to a CTMC, consider using a CTMC instead.");
639 result = model->convertToCtmc();
640 }
641
642 if (transformationSettings.isChainEliminationSet()) {
643 if constexpr (storm::IsIntervalType<ValueType>) {
644 // Currently not enabling this for interval models, as this would require a number of additional template instantiations.
645 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Chain elimination not supported for interval models.");
646 } else {
647 // TODO: we should also transform the properties at this point.
649 transformationSettings.getLabelBehavior())
650 .first;
651 }
652 }
653
654 return result;
655}
656
657template<typename ValueType>
658std::shared_ptr<storm::models::sparse::Model<ValueType>> preprocessSparseModelBisimulation(
659 std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input,
660 storm::settings::modules::BisimulationSettings const& bisimulationSettings, bool graphPreserving = true) {
662 if (bisimulationSettings.isWeakBisimulationSet()) {
664 }
665
666 STORM_LOG_INFO("Performing bisimulation minimization...");
667 return storm::api::performBisimulationMinimization<ValueType>(model, createFormulasToRespect(input.properties), bisimType, graphPreserving);
668}
669
670template<typename ValueType>
671std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model,
672 SymbolicInput const& input, ModelProcessingInformation const& mpi) {
673 STORM_LOG_THROW(mpi.buildValueType == mpi.verificationValueType, storm::exceptions::NotSupportedException,
674 "Converting value types for sparse engine is not supported.");
675 auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>();
676 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
677 auto transformationSettings = storm::settings::getModule<storm::settings::modules::TransformationSettings>();
678
679 std::pair<std::shared_ptr<storm::models::sparse::Model<ValueType>>, bool> result = std::make_pair(model, false);
680
681 if (auto order = transformationSettings.getModelPermutation(); order.has_value()) {
682 auto seed = transformationSettings.getModelPermutationSeed();
683 STORM_PRINT_AND_LOG("Permuting model states using " << storm::utility::permutation::orderKindtoString(order.value()) << " order"
684 << (seed.has_value() ? " with seed " + std::to_string(seed.value()) : "") << ".\n");
685 result.first = storm::api::permuteModelStates(result.first, order.value(), seed);
686 result.second = true;
687 STORM_PRINT_AND_LOG("Transition matrix hash after permuting: " << result.first->getTransitionMatrix().hash() << ".\n");
688 }
689
690 if (result.first->isOfType(storm::models::ModelType::MarkovAutomaton)) {
692 result.second = true;
693 }
694
695 if (mpi.applyBisimulation) {
696 if constexpr (storm::IsIntervalType<ValueType>) {
697 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Bisimulation not supported for interval models.");
698 } else {
699 result.first = preprocessSparseModelBisimulation(result.first, input, bisimulationSettings);
700 result.second = true;
701 }
702 }
703
704 if (transformationSettings.isToDiscreteTimeModelSet()) {
705 if constexpr (storm::IsIntervalType<ValueType>) {
706 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation to discrete time model not supported for interval models.");
707 } else {
708 // TODO: we should also transform the properties at this point.
710 !model->hasRewardModel("_time"),
711 "Scheduled transformation to discrete time model, but a reward model named '_time' is already present in this model. We might take "
712 "the wrong reward model later.");
713 result.first =
715 .first;
716 result.second = true;
717 }
718 }
719
720 if (transformationSettings.isToNondeterministicModelSet()) {
721 result.first = storm::api::transformToNondeterministicModel<ValueType>(std::move(*result.first));
722 result.second = true;
723 }
724
725 return result;
726}
727
728template<typename ValueType>
729void exportModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input) {
730 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
731
732 if (ioSettings.isExportBuildSet()) {
733 switch (ioSettings.getExportBuildFormat()) {
735 storm::api::exportSparseModelAsDot(model, ioSettings.getExportBuildFilename(), ioSettings.getExportDotMaxWidth());
736 break;
738 storm::api::exportSparseModelAsDrn(model, ioSettings.getExportBuildFilename(),
739 input.model ? input.model.get().getParameterNames() : std::vector<std::string>(),
740 !ioSettings.isExplicitExportPlaceholdersDisabled());
741 break;
743 storm::api::exportSparseModelAsJson(model, ioSettings.getExportBuildFilename());
744 break;
745 default:
746 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException,
747 "Exporting sparse models in " << storm::io::toString(ioSettings.getExportBuildFormat()) << " format is not supported.");
748 }
749 }
750
751 // TODO: The following options are depreciated and shall be removed at some point:
752
753 if (ioSettings.isExportExplicitSet()) {
754 storm::api::exportSparseModelAsDrn(model, ioSettings.getExportExplicitFilename(),
755 input.model ? input.model.get().getParameterNames() : std::vector<std::string>(),
756 !ioSettings.isExplicitExportPlaceholdersDisabled());
757 }
758
759 if (ioSettings.isExportDdSet()) {
760 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Exporting in drdd format is only supported for DDs.");
761 }
762
763 if (ioSettings.isExportDotSet()) {
764 storm::api::exportSparseModelAsDot(model, ioSettings.getExportDotFilename(), ioSettings.getExportDotMaxWidth());
765 }
766}
767
768template<storm::dd::DdType DdType, typename ValueType>
770 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
771
772 if (ioSettings.isExportBuildSet()) {
773 switch (ioSettings.getExportBuildFormat()) {
775 storm::api::exportSymbolicModelAsDot(model, ioSettings.getExportBuildFilename());
776 break;
778 storm::api::exportSymbolicModelAsDrdd(model, ioSettings.getExportBuildFilename());
779 break;
780 default:
781 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException,
782 "Exporting symbolic models in " << storm::io::toString(ioSettings.getExportBuildFormat()) << " format is not supported.");
783 }
784 }
785
786 // TODO: The following options are depreciated and shall be removed at some point:
787
788 if (ioSettings.isExportExplicitSet()) {
789 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Exporting in drn format is only supported for sparse models.");
790 }
791
792 if (ioSettings.isExportDdSet()) {
793 storm::api::exportSymbolicModelAsDrdd(model, ioSettings.getExportDdFilename());
794 }
795
796 if (ioSettings.isExportDotSet()) {
797 storm::api::exportSymbolicModelAsDot(model, ioSettings.getExportDotFilename());
798 }
799}
800
801template<storm::dd::DdType DdType, typename ValueType>
802typename std::enable_if<DdType != storm::dd::DdType::Sylvan && !std::is_same<ValueType, double>::value, std::shared_ptr<storm::models::Model<ValueType>>>::type
804 return model;
805}
806
807template<storm::dd::DdType DdType, typename ValueType>
808typename std::enable_if<DdType == storm::dd::DdType::Sylvan || std::is_same<ValueType, double>::value, std::shared_ptr<storm::models::Model<ValueType>>>::type
810 auto ma = model->template as<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>>();
811 if (!ma->isClosed()) {
812 return std::make_shared<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>>(ma->close());
813 } else {
814 return model;
815 }
816}
817
818template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType = ValueType>
819std::shared_ptr<storm::models::Model<ExportValueType>> preprocessDdModelBisimulation(
820 std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input,
821 storm::settings::modules::BisimulationSettings const& bisimulationSettings, ModelProcessingInformation const& mpi) {
822 STORM_LOG_WARN_COND(!bisimulationSettings.isWeakBisimulationSet(),
823 "Weak bisimulation is currently not supported on DDs. Falling back to strong bisimulation.");
824
825 auto quotientFormat = bisimulationSettings.getQuotientFormat();
827 bisimulationSettings.isQuotientFormatSetFromDefaultValue()) {
828 STORM_LOG_INFO("Setting bisimulation quotient format to 'sparse'.");
830 }
831 STORM_LOG_INFO("Performing bisimulation minimization...");
832 return storm::api::performBisimulationMinimization<DdType, ValueType, ExportValueType>(
833 model, createFormulasToRespect(input.properties), storm::storage::BisimulationType::Strong, bisimulationSettings.getSignatureMode(), quotientFormat);
834}
835
836template<typename ExportValueType, storm::dd::DdType DdType, typename ValueType>
837std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessDdModelImpl(
838 std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input, ModelProcessingInformation const& mpi) {
839 auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>();
840 std::pair<std::shared_ptr<storm::models::Model<ValueType>>, bool> intermediateResult = std::make_pair(model, false);
841
842 if (model->isOfType(storm::models::ModelType::MarkovAutomaton)) {
843 intermediateResult.first = preprocessDdMarkovAutomaton(intermediateResult.first->template as<storm::models::symbolic::Model<DdType, ValueType>>());
844 intermediateResult.second = true;
845 }
846
847 std::unique_ptr<std::pair<std::shared_ptr<storm::models::Model<ExportValueType>>, bool>> result;
848 auto symbolicModel = intermediateResult.first->template as<storm::models::symbolic::Model<DdType, ValueType>>();
849 if (mpi.applyBisimulation) {
850 std::shared_ptr<storm::models::Model<ExportValueType>> newModel =
851 preprocessDdModelBisimulation<DdType, ValueType, ExportValueType>(symbolicModel, input, bisimulationSettings, mpi);
852 result = std::make_unique<std::pair<std::shared_ptr<storm::models::Model<ExportValueType>>, bool>>(newModel, true);
853 } else {
854 result = std::make_unique<std::pair<std::shared_ptr<storm::models::Model<ExportValueType>>, bool>>(
855 symbolicModel->template toValueType<ExportValueType>(), !std::is_same<ValueType, ExportValueType>::value);
856 }
857
858 if (result && result->first->isSymbolicModel() && mpi.engine == storm::utility::Engine::DdSparse) {
859 // Mark as changed.
860 result->second = true;
861
862 std::shared_ptr<storm::models::symbolic::Model<DdType, ExportValueType>> symbolicModel =
863 result->first->template as<storm::models::symbolic::Model<DdType, ExportValueType>>();
864 std::vector<std::shared_ptr<storm::logic::Formula const>> formulas;
865 for (auto const& property : input.properties) {
866 formulas.emplace_back(property.getRawFormula());
867 }
868 result->first = storm::api::transformSymbolicToSparseModel(symbolicModel, formulas);
869 STORM_LOG_THROW(result, storm::exceptions::NotSupportedException, "The translation to a sparse model is not supported for the given model type.");
870 }
871
872 return *result;
873}
874
875template<storm::dd::DdType DdType, typename ValueType>
876std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessModel(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model,
877 SymbolicInput const& input, ModelProcessingInformation const& mpi) {
878 return applyValueType(mpi.verificationValueType, [&model, &input, &mpi]<typename VT>() -> std::pair<std::shared_ptr<storm::models::ModelBase>, bool> {
879 // To safe a few template instantiations, we only consider those combinations that actually occur in the CLI
880 if constexpr (std::is_same_v<ValueType, VT> ||
881 (DdType == storm::dd::DdType::Sylvan && std::is_same_v<ValueType, storm::RationalNumber> && std::is_same_v<VT, double>)) {
882 return preprocessDdModelImpl<VT>(model, input, mpi);
883 } else {
884 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException,
885 "Unexpected combination of DD library, build value type, and verification value type.");
886 }
887 });
888}
889
891 STORM_PRINT("Computing counterexample for property " << *property.getRawFormula() << " ...\n");
892}
893
894inline void printCounterexample(std::shared_ptr<storm::counterexamples::Counterexample> const& counterexample, storm::utility::Stopwatch* watch = nullptr) {
895 if (counterexample) {
896 STORM_PRINT(*counterexample << '\n');
897 if (watch) {
898 STORM_PRINT("Time for computation: " << *watch << ".\n");
899 }
900 } else {
901 STORM_PRINT(" failed.\n");
902 }
903}
904
905template<typename ModelType>
906 requires(!std::derived_from<ModelType, storm::models::sparse::Model<double>>)
907inline void generateCounterexamples(std::shared_ptr<ModelType> const&, SymbolicInput const&) {
908 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Counterexample generation is not supported for this data-type.");
909}
910
911template<typename ModelType>
912 requires(std::derived_from<ModelType, storm::models::sparse::Model<double>>)
913inline void generateCounterexamples(std::shared_ptr<ModelType> const& sparseModel, SymbolicInput const& input) {
914 using ValueType = typename ModelType::ValueType;
915
916 for (auto& rewModel : sparseModel->getRewardModels()) {
917 rewModel.second.reduceToStateBasedRewards(sparseModel->getTransitionMatrix(), true);
918 }
919
920 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Dtmc) || sparseModel->isOfType(storm::models::ModelType::Mdp),
921 storm::exceptions::NotSupportedException, "Counterexample is currently only supported for discrete-time models.");
922
923 auto counterexampleSettings = storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>();
924 if (counterexampleSettings.isMinimalCommandSetGenerationSet()) {
925 bool useMilp = counterexampleSettings.isUseMilpBasedMinimalCommandSetGenerationSet();
926 for (auto const& property : input.properties) {
927 std::shared_ptr<storm::counterexamples::Counterexample> counterexample;
929 storm::utility::Stopwatch watch(true);
930 if (useMilp) {
931 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException,
932 "Counterexample generation using MILP is currently only supported for MDPs.");
934 input.model.get(), sparseModel->template as<storm::models::sparse::Mdp<ValueType>>(), property.getRawFormula());
935 } else {
936 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Dtmc) || sparseModel->isOfType(storm::models::ModelType::Mdp),
937 storm::exceptions::NotSupportedException,
938 "Counterexample generation using MaxSAT is currently only supported for discrete-time models.");
939
940 if (sparseModel->isOfType(storm::models::ModelType::Dtmc)) {
942 input.model.get(), sparseModel->template as<storm::models::sparse::Dtmc<ValueType>>(), property.getRawFormula());
943 } else {
945 input.model.get(), sparseModel->template as<storm::models::sparse::Mdp<ValueType>>(), property.getRawFormula());
946 }
947 }
948 watch.stop();
949 printCounterexample(counterexample, &watch);
950 }
951 } else if (counterexampleSettings.isShortestPathGenerationSet()) {
952 for (auto const& property : input.properties) {
953 std::shared_ptr<storm::counterexamples::Counterexample> counterexample;
955 storm::utility::Stopwatch watch(true);
956 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Dtmc), storm::exceptions::NotSupportedException,
957 "Counterexample generation using shortest paths is currently only supported for DTMCs.");
959 property.getRawFormula(), counterexampleSettings.getShortestPathMaxK());
960 watch.stop();
961 printCounterexample(counterexample, &watch);
962 }
963 } else {
964 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The selected counterexample formalism is unsupported.");
965 }
966}
967
968template<typename ValueType>
969 requires(!storm::IsIntervalType<ValueType>)
970void printFilteredResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::modelchecker::FilterType ft) {
971 if (result->isQuantitative()) {
973 STORM_PRINT(*result);
974 } else {
975 ValueType resultValue;
976 switch (ft) {
978 resultValue = result->asQuantitativeCheckResult<ValueType>().sum();
979 break;
981 resultValue = result->asQuantitativeCheckResult<ValueType>().average();
982 break;
984 resultValue = result->asQuantitativeCheckResult<ValueType>().getMin();
985 break;
987 resultValue = result->asQuantitativeCheckResult<ValueType>().getMax();
988 break;
991 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Outputting states is not supported.");
995 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Filter type only defined for qualitative results.");
996 default:
997 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Unhandled filter type.");
998 }
1000 STORM_PRINT(resultValue << " (approx. " << storm::utility::convertNumber<double>(resultValue) << ")");
1001 } else {
1002 STORM_PRINT(resultValue);
1003 }
1004 }
1005 } else {
1006 switch (ft) {
1008 STORM_PRINT(*result << '\n');
1009 break;
1011 STORM_PRINT(result->asQualitativeCheckResult().existsTrue());
1012 break;
1014 STORM_PRINT(result->asQualitativeCheckResult().forallTrue());
1015 break;
1017 STORM_PRINT(result->asQualitativeCheckResult().count());
1018 break;
1021 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Outputting states is not supported.");
1026 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Filter type only defined for quantitative results.");
1027 }
1028 }
1029 STORM_PRINT('\n');
1030}
1031
1033 STORM_PRINT("\nModel checking property \"" << property.getName() << "\": " << *property.getRawFormula() << " ...\n");
1034}
1035
1036template<typename ValueType>
1037 requires(!storm::IsIntervalType<ValueType>)
1038void printResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::logic::Formula const& filterStatesFormula,
1039 storm::modelchecker::FilterType const& filterType, storm::utility::Stopwatch* watch = nullptr) {
1040 if (result) {
1041 std::stringstream ss;
1042 ss << "'" << filterStatesFormula << "'";
1043 STORM_PRINT((storm::utility::resources::isTerminate() ? "Result till abort" : "Result")
1044 << " (for " << (filterStatesFormula.isInitialFormula() ? "initial" : ss.str()) << " states): ");
1045 printFilteredResult<ValueType>(result, filterType);
1046 if (watch) {
1047 STORM_PRINT("Time for model checking: " << *watch << ".\n");
1048 }
1049 } else {
1050 STORM_LOG_ERROR("Property is unsupported by selected engine/settings.\n");
1051 }
1052}
1053
1054template<typename ValueType>
1055void printResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::jani::Property const& property,
1056 storm::utility::Stopwatch* watch = nullptr) {
1057 printResult<ValueType>(result, *property.getFilter().getStatesFormula(), property.getFilter().getFilterType(), watch);
1058}
1059
1060using VerificationCallbackType = std::function<std::unique_ptr<storm::modelchecker::CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula,
1061 std::shared_ptr<storm::logic::Formula const> const& states)>;
1062using PostprocessingCallbackType = std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)>;
1063
1065 void operator()(std::unique_ptr<storm::modelchecker::CheckResult> const&) {
1066 // Intentionally left empty.
1067 }
1068};
1069
1076template<typename ValueType>
1077std::unique_ptr<storm::modelchecker::CheckResult> verifyProperty(std::shared_ptr<storm::logic::Formula const> const& formula,
1078 std::shared_ptr<storm::logic::Formula const> const& statesFilter,
1079 VerificationCallbackType const& verificationCallback) {
1080 auto transformationSettings = storm::settings::getModule<storm::settings::modules::TransformationSettings>();
1081
1082 try {
1083 if constexpr (storm::IsIntervalType<ValueType>) {
1084 STORM_LOG_ASSERT(!transformationSettings.isChainEliminationSet() && !transformationSettings.isToNondeterministicModelSet(),
1085 "Unsupported transformation has been invoked.");
1086 return verificationCallback(formula, statesFilter);
1087 }
1088 if (transformationSettings.isChainEliminationSet() && !storm::transformer::NonMarkovianChainTransformer<ValueType>::preservesFormula(*formula)) {
1089 STORM_LOG_WARN("Property is not preserved by elimination of non-markovian states.");
1090 } else if (transformationSettings.isToDiscreteTimeModelSet()) {
1091 auto transformedFormula = storm::api::checkAndTransformContinuousToDiscreteTimeFormula<ValueType>(*formula);
1092 auto transformedStatesFilter = storm::api::checkAndTransformContinuousToDiscreteTimeFormula<ValueType>(*statesFilter);
1093 if (transformedFormula && transformedStatesFilter) {
1094 // invoke verification algorithm on transformed formulas
1095 return verificationCallback(transformedFormula, transformedStatesFilter);
1096 } else {
1097 STORM_LOG_WARN("Property is not preserved by transformation to discrete time model.");
1098 }
1099 } else {
1100 // invoke verification algorithm on given formulas
1101 return verificationCallback(formula, statesFilter);
1102 }
1103 } catch (storm::exceptions::BaseException const& ex) {
1104 STORM_LOG_WARN("Cannot handle property: " << ex.what());
1105 }
1106 return nullptr;
1107}
1108
1115template<typename ValueType>
1116void verifyProperties(SymbolicInput const& input, VerificationCallbackType const& verificationCallback,
1117 PostprocessingCallbackType const& postprocessingCallback = PostprocessingIdentity()) {
1118 auto const& properties = input.preprocessedProperties ? input.preprocessedProperties.get() : input.properties;
1119 for (auto const& property : properties) {
1121 storm::utility::Stopwatch watch(true);
1122 auto result = verifyProperty<ValueType>(property.getRawFormula(), property.getFilter().getStatesFormula(), verificationCallback);
1123 watch.stop();
1124 if (result) {
1125 postprocessingCallback(result);
1126 }
1127 printResult<storm::IntervalBaseType<ValueType>>(result, property, &watch);
1128 }
1129}
1130
1140template<typename ValueType>
1141void computeStateValues(std::string const& description, std::function<std::unique_ptr<storm::modelchecker::CheckResult>()> const& computationCallback,
1142 SymbolicInput const& input, VerificationCallbackType const& verificationCallback,
1143 PostprocessingCallbackType const& postprocessingCallback = PostprocessingIdentity()) {
1144 // First compute the state values for all the states by invoking the computationCallback
1145 storm::utility::Stopwatch watch(true);
1146 STORM_PRINT("\nComputing " << description << " ...\n");
1147 std::unique_ptr<storm::modelchecker::CheckResult> result;
1148 try {
1149 result = computationCallback();
1150 } catch (storm::exceptions::BaseException const& ex) {
1151 STORM_LOG_ERROR("Cannot compute " << description << ": " << ex.what());
1152 }
1153 if (!result) {
1154 STORM_LOG_ERROR("Computation had no result.");
1155 return;
1156 }
1157 // Now process the (potentially filtered) result
1158 if (input.properties.empty()) {
1159 // Do not apply any filtering, consider result for *all* states
1160 postprocessingCallback(result);
1161 printResult<ValueType>(result, *storm::logic::Formula::getTrueFormula(), storm::modelchecker::FilterType::VALUES, &watch);
1162 } else {
1163 // Each property identifies a subset of states to which we restrict (aka filter) the state-value result to
1164 auto const& properties = input.preprocessedProperties ? input.preprocessedProperties.get() : input.properties;
1165 for (uint64_t propertyIndex = 0; propertyIndex < properties.size(); ++propertyIndex) {
1166 auto const& property = properties[propertyIndex];
1167 // As the property serves as filter, it should (a) be qualitative and should (b) not consider a filter itself.
1168 if (!property.getRawFormula()->hasQualitativeResult()) {
1169 STORM_LOG_ERROR("Property '" << *property.getRawFormula()
1170 << "' can not be used for filtering states as it does not have a qualitative result.");
1171 continue;
1172 }
1173
1174 // Invoke verification algorithm on filtering property
1175 auto propertyFilter = verifyProperty<ValueType>(property.getRawFormula(), storm::logic::Formula::getTrueFormula(), verificationCallback);
1176
1177 if (propertyFilter) {
1178 // Filter and process result
1179 std::unique_ptr<storm::modelchecker::CheckResult> filteredResult = result->clone();
1180 filteredResult->filter(propertyFilter->asQualitativeCheckResult());
1181 postprocessingCallback(filteredResult);
1182 printResult<ValueType>(filteredResult, *property.getRawFormula(), property.getFilter().getFilterType(),
1183 propertyIndex == properties.size() - 1 ? &watch : nullptr);
1184 }
1185 }
1186 }
1187}
1188
1189inline std::vector<storm::expressions::Expression> parseConstraints(storm::expressions::ExpressionManager const& expressionManager,
1190 std::string const& constraintsString) {
1191 std::vector<storm::expressions::Expression> constraints;
1192
1193 std::vector<std::string> constraintsAsStrings;
1194 boost::split(constraintsAsStrings, constraintsString, boost::is_any_of(","));
1195
1196 storm::parser::ExpressionParser expressionParser(expressionManager);
1197 std::unordered_map<std::string, storm::expressions::Expression> variableMapping;
1198 for (auto const& variableTypePair : expressionManager) {
1199 variableMapping[variableTypePair.first.getName()] = variableTypePair.first;
1200 }
1201 expressionParser.setIdentifierMapping(variableMapping);
1202
1203 for (auto const& constraintString : constraintsAsStrings) {
1204 if (constraintString.empty()) {
1205 continue;
1206 }
1207
1208 storm::expressions::Expression constraint = expressionParser.parseFromString(constraintString);
1209 STORM_LOG_TRACE("Adding special (user-provided) constraint " << constraint << ".");
1210 constraints.emplace_back(constraint);
1211 }
1212
1213 return constraints;
1214}
1215
1216inline std::vector<std::vector<storm::expressions::Expression>> parseInjectedRefinementPredicates(
1217 storm::expressions::ExpressionManager const& expressionManager, std::string const& refinementPredicatesString) {
1218 std::vector<std::vector<storm::expressions::Expression>> injectedRefinementPredicates;
1219
1220 storm::parser::ExpressionParser expressionParser(expressionManager);
1221 std::unordered_map<std::string, storm::expressions::Expression> variableMapping;
1222 for (auto const& variableTypePair : expressionManager) {
1223 variableMapping[variableTypePair.first.getName()] = variableTypePair.first;
1224 }
1225 expressionParser.setIdentifierMapping(variableMapping);
1226
1227 std::vector<std::string> predicateGroupsAsStrings;
1228 boost::split(predicateGroupsAsStrings, refinementPredicatesString, boost::is_any_of(";"));
1229
1230 if (!predicateGroupsAsStrings.empty()) {
1231 for (auto const& predicateGroupString : predicateGroupsAsStrings) {
1232 if (predicateGroupString.empty()) {
1233 continue;
1234 }
1235
1236 std::vector<std::string> predicatesAsStrings;
1237 boost::split(predicatesAsStrings, predicateGroupString, boost::is_any_of(":"));
1238
1239 if (!predicatesAsStrings.empty()) {
1240 injectedRefinementPredicates.emplace_back();
1241 for (auto const& predicateString : predicatesAsStrings) {
1242 storm::expressions::Expression predicate = expressionParser.parseFromString(predicateString);
1243 STORM_LOG_TRACE("Adding special (user-provided) refinement predicate " << predicateString << ".");
1244 injectedRefinementPredicates.back().emplace_back(predicate);
1245 }
1246
1247 STORM_LOG_THROW(!injectedRefinementPredicates.back().empty(), storm::exceptions::InvalidArgumentException,
1248 "Expecting non-empty list of predicates to inject for each (mentioned) refinement step.");
1249
1250 // Finally reverse the list, because we take the predicates from the back.
1251 std::reverse(injectedRefinementPredicates.back().begin(), injectedRefinementPredicates.back().end());
1252 }
1253 }
1254
1255 // Finally reverse the list, because we take the predicates from the back.
1256 std::reverse(injectedRefinementPredicates.begin(), injectedRefinementPredicates.end());
1257 }
1258
1259 return injectedRefinementPredicates;
1260}
1261
1262template<storm::dd::DdType DdType, typename ValueType>
1264 STORM_LOG_ASSERT(input.model, "Expected symbolic model description.");
1265 storm::settings::modules::AbstractionSettings const& abstractionSettings = storm::settings::getModule<storm::settings::modules::AbstractionSettings>();
1267 parseConstraints(input.model->getManager(), abstractionSettings.getConstraintString()),
1268 parseInjectedRefinementPredicates(input.model->getManager(), abstractionSettings.getInjectedRefinementPredicates()));
1269
1270 verifyProperties<ValueType>(input, [&input, &options, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula,
1271 std::shared_ptr<storm::logic::Formula const> const& states) {
1272 STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Abstraction-refinement can only filter initial states.");
1273 return storm::gbar::api::verifyWithAbstractionRefinementEngine<DdType, ValueType>(mpi.env, input.model.get(),
1274 storm::api::createTask<ValueType>(formula, true), options);
1275 });
1276}
1277
1278template<typename ValueType>
1280 STORM_LOG_ASSERT(input.model, "Expected symbolic model description.");
1281 STORM_LOG_THROW((std::is_same<ValueType, double>::value), storm::exceptions::NotSupportedException,
1282 "Exploration does not support other data-types than floating points.");
1283 verifyProperties<ValueType>(
1284 input, [&input, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
1285 STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Exploration can only filter initial states.");
1286 return storm::api::verifyWithExplorationEngine<ValueType>(mpi.env, input.model.get(), storm::api::createTask<ValueType>(formula, true));
1287 });
1288}
1289
1290template<typename ValueType>
1291void verifyModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& sparseModel, SymbolicInput const& input,
1292 ModelProcessingInformation const& mpi) {
1293 auto const& ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
1294 auto verificationCallback = [&sparseModel, &ioSettings, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula,
1295 std::shared_ptr<storm::logic::Formula const> const& states) {
1296 bool filterForInitialStates = states->isInitialFormula();
1297 auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates);
1298 if (ioSettings.isExportSchedulerSet()) {
1299 task.setProduceSchedulers(true);
1300 }
1301 std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(mpi.env, sparseModel, task);
1302
1303 std::unique_ptr<storm::modelchecker::CheckResult> filter;
1304 if (filterForInitialStates) {
1305 filter = std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult>(sparseModel->getInitialStates());
1306 } else if (!states->isTrueFormula()) { // No need to apply filter if it is the formula 'true'
1307 filter = storm::api::verifyWithSparseEngine<ValueType>(mpi.env, sparseModel, storm::api::createTask<ValueType>(states, false));
1308 }
1309 if (result && filter) {
1310 result->filter(filter->asQualitativeCheckResult());
1311 }
1312 return result;
1313 };
1314 uint64_t exportCount = 0; // this number will be prepended to the export file name of schedulers and/or check results in case of multiple properties.
1315 auto postprocessingCallback = [&sparseModel, &ioSettings, &input, &exportCount](std::unique_ptr<storm::modelchecker::CheckResult> const& result) {
1316 // Scheduler export
1317 STORM_LOG_WARN_COND(!ioSettings.isExportSchedulerSet() || result->hasScheduler(), "Scheduler requested but could not be generated.");
1318 if (ioSettings.isExportSchedulerSet() && result->hasScheduler()) {
1319 std::filesystem::path schedulerExportPath = ioSettings.getExportSchedulerFilename();
1320 if (exportCount > 0) {
1321 STORM_LOG_WARN("Prepending " << exportCount << " to scheduler file name for this property because there are multiple properties.");
1322 schedulerExportPath.replace_filename(std::to_string(exportCount) + schedulerExportPath.filename().string());
1323 }
1324 STORM_PRINT_AND_LOG("Exporting scheduler ... ");
1325 if (input.model) {
1326 STORM_LOG_WARN_COND(sparseModel->hasStateValuations(),
1327 "No information of state valuations available. The scheduler output will use internal state ids. You might be "
1328 "interested in building the model with state valuations using --buildstateval.");
1330 sparseModel->hasChoiceLabeling() || sparseModel->hasChoiceOrigins(),
1331 "No symbolic choice information is available. The scheduler output will use internal choice ids. You might be interested in "
1332 "building the model with choice labels or choice origins using --buildchoicelab or --buildchoiceorig.");
1333 STORM_LOG_WARN_COND(sparseModel->hasChoiceLabeling() && !sparseModel->hasChoiceOrigins(),
1334 "Only partial choice information is available. You might want to build the model with choice origins using "
1335 "--buildchoicelab or --buildchoiceorig.");
1336 }
1337 if (result->isExplicitQuantitativeCheckResult()) {
1338 if constexpr (storm::IsIntervalType<ValueType>) {
1339 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export for interval models is not supported.");
1340 } else {
1341 storm::api::exportScheduler(sparseModel, result->template asExplicitQuantitativeCheckResult<ValueType>().getScheduler(),
1342 schedulerExportPath.string());
1343 }
1344 } else if (result->isExplicitParetoCurveCheckResult()) {
1345 if constexpr (std::is_same_v<ValueType, storm::RationalFunction> || storm::IsIntervalType<ValueType>) {
1346 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export for models of this value type is not supported.");
1347 } else {
1348 auto const& paretoRes = result->template asExplicitParetoCurveCheckResult<ValueType>();
1349 storm::api::exportParetoScheduler(sparseModel, paretoRes.getPoints(), paretoRes.getSchedulers(), schedulerExportPath.string());
1350 }
1351 } else {
1352 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export not supported for this value type.");
1353 }
1354 }
1355
1356 // Result export
1357 if (ioSettings.isExportCheckResultSet()) {
1358 if constexpr (storm::IsIntervalType<ValueType>) {
1359 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Result export for interval models is not supported.");
1360 } else {
1361 std::filesystem::path resultExportPath = ioSettings.getExportCheckResultFilename();
1362 if (exportCount > 0) {
1363 STORM_LOG_WARN("Prepending " << exportCount << " to result file name for this property because there are multiple properties.");
1364 resultExportPath.replace_filename(std::to_string(exportCount) + resultExportPath.filename().string());
1365 }
1366 STORM_LOG_WARN_COND(sparseModel->hasStateValuations(),
1367 "No information of state valuations available. The result output will use internal state ids. You might be interested in "
1368 "building the model with state valuations using --buildstateval.");
1369 storm::api::exportCheckResultToJson(sparseModel, result, resultExportPath);
1370 }
1371 }
1372 ++exportCount;
1373 };
1374 if (!(ioSettings.isComputeSteadyStateDistributionSet() || ioSettings.isComputeExpectedVisitingTimesSet())) {
1375 verifyProperties<ValueType>(input, verificationCallback, postprocessingCallback);
1376 }
1377 if (ioSettings.isComputeSteadyStateDistributionSet()) {
1378 if constexpr (storm::IsIntervalType<ValueType>) {
1379 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Computing steady state distribution is not supported for interval models.");
1380 } else {
1381 computeStateValues<ValueType>(
1382 "steady-state probabilities",
1383 [&mpi, &sparseModel]() { return storm::api::computeSteadyStateDistributionWithSparseEngine<ValueType>(mpi.env, sparseModel); }, input,
1384 verificationCallback, postprocessingCallback);
1385 }
1386 }
1387 if (ioSettings.isComputeExpectedVisitingTimesSet()) {
1388 if constexpr (storm::IsIntervalType<ValueType>) {
1389 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Computing expected visiting times is not supported for interval models.");
1390 } else {
1391 computeStateValues<ValueType>(
1392 "expected visiting times",
1393 [&mpi, &sparseModel]() { return storm::api::computeExpectedVisitingTimesWithSparseEngine<ValueType>(mpi.env, sparseModel); }, input,
1394 verificationCallback, postprocessingCallback);
1395 }
1396 }
1397}
1398
1399template<storm::dd::DdType DdType, typename ValueType>
1400void verifyWithHybridEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& symbolicModel, SymbolicInput const& input,
1401 ModelProcessingInformation const& mpi) {
1402 verifyProperties<ValueType>(
1403 input, [&symbolicModel, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
1404 bool filterForInitialStates = states->isInitialFormula();
1405 auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates);
1406
1407 std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithHybridEngine<DdType, ValueType>(mpi.env, symbolicModel, task);
1408
1409 std::unique_ptr<storm::modelchecker::CheckResult> filter;
1410 if (filterForInitialStates) {
1411 filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(),
1412 symbolicModel->getInitialStates());
1413 } else if (!states->isTrueFormula()) { // No need to apply filter if it is the formula 'true'
1414 filter = storm::api::verifyWithHybridEngine<DdType, ValueType>(mpi.env, symbolicModel, storm::api::createTask<ValueType>(states, false));
1415 }
1416 if (result && filter) {
1417 result->filter(filter->asQualitativeCheckResult());
1418 }
1419 return result;
1420 });
1421}
1422
1423template<storm::dd::DdType DdType, typename ValueType>
1424void verifyWithDdEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& symbolicModel, SymbolicInput const& input,
1425 ModelProcessingInformation const& mpi) {
1426 verifyProperties<ValueType>(
1427 input, [&symbolicModel, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
1428 bool filterForInitialStates = states->isInitialFormula();
1429 auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates);
1430
1431 std::unique_ptr<storm::modelchecker::CheckResult> result =
1432 storm::api::verifyWithDdEngine<DdType, ValueType>(mpi.env, symbolicModel, storm::api::createTask<ValueType>(formula, true));
1433
1434 std::unique_ptr<storm::modelchecker::CheckResult> filter;
1435 if (filterForInitialStates) {
1436 filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(),
1437 symbolicModel->getInitialStates());
1438 } else if (!states->isTrueFormula()) { // No need to apply filter if it is the formula 'true'
1439 filter = storm::api::verifyWithDdEngine<DdType, ValueType>(mpi.env, symbolicModel, storm::api::createTask<ValueType>(states, false));
1440 }
1441 if (result && filter) {
1442 result->filter(filter->asQualitativeCheckResult());
1443 }
1444 return result;
1445 });
1446}
1447
1448template<storm::dd::DdType DdType, typename ValueType>
1450 ModelProcessingInformation const& mpi) {
1451 verifyProperties<ValueType>(
1452 input, [&symbolicModel, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
1453 STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Abstraction-refinement can only filter initial states.");
1454 return storm::gbar::api::verifyWithAbstractionRefinementEngine<DdType, ValueType>(mpi.env, symbolicModel,
1455 storm::api::createTask<ValueType>(formula, true));
1456 });
1457}
1458
1459template<storm::dd::DdType DdType, typename ValueType>
1460typename std::enable_if<DdType != storm::dd::DdType::CUDD || std::is_same<ValueType, double>::value, void>::type verifyModel(
1461 std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& symbolicModel, SymbolicInput const& input,
1462 ModelProcessingInformation const& mpi) {
1464 verifyWithHybridEngine<DdType, ValueType>(symbolicModel, input, mpi);
1465 } else if (mpi.engine == storm::utility::Engine::Dd) {
1466 verifyWithDdEngine<DdType, ValueType>(symbolicModel, input, mpi);
1467 } else {
1468 verifyWithAbstractionRefinementEngine<DdType, ValueType>(symbolicModel, input, mpi);
1469 }
1470}
1471
1472template<storm::dd::DdType DdType, typename ValueType>
1473typename std::enable_if<DdType == storm::dd::DdType::CUDD && !std::is_same<ValueType, double>::value, void>::type verifySymbolicModel(
1474 std::shared_ptr<storm::models::ModelBase> const&, SymbolicInput const&, ModelProcessingInformation const&) {
1475 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "CUDD does not support the selected data-type.");
1476}
1477
1478inline std::shared_ptr<storm::models::ModelBase> buildPreprocessModel(SymbolicInput const& input, ModelProcessingInformation const& mpi) {
1479 auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
1480 auto buildSettings = storm::settings::getModule<storm::settings::modules::BuildSettings>();
1481
1482 std::shared_ptr<storm::models::ModelBase> model;
1483 if (!buildSettings.isNoBuildModelSet()) {
1484 model = buildModel(input, ioSettings, mpi);
1485 }
1486 if (!model) {
1487 STORM_LOG_THROW(input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model.");
1488 return nullptr;
1489 }
1490 model->printModelInformationToStream(std::cout);
1491
1492 storm::utility::Stopwatch preprocessingWatch(true);
1493 auto preprocessingResult = castAndApply(model, [&input, &mpi](auto const& m) { return preprocessModel(m, input, mpi); });
1494 preprocessingWatch.stop();
1495 if (preprocessingResult.second) {
1496 STORM_PRINT("\nTime for model preprocessing: " << preprocessingWatch << ".\n\n");
1497 model = preprocessingResult.first;
1498 model->printModelInformationToStream(std::cout);
1499 }
1500
1501 return model;
1502}
1503
1504inline std::shared_ptr<storm::models::ModelBase> buildPreprocessExportModel(SymbolicInput const& input, ModelProcessingInformation const& mpi) {
1505 auto model = buildPreprocessModel(input, mpi);
1506 if (model) {
1507 castAndApply(model, [&input](auto const& m) { exportModel(m, input); });
1508 }
1509 return model;
1510}
1511
1512inline void processInput(SymbolicInput const& input, ModelProcessingInformation const& mpi) {
1513 auto abstractionSettings = storm::settings::getModule<storm::settings::modules::AbstractionSettings>();
1514 auto counterexampleSettings = storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>();
1515
1516 // For several engines, no model building step is performed, but the verification is started right away.
1518 abstractionSettings.getAbstractionRefinementMethod() == storm::settings::modules::AbstractionSettings::Method::Games) {
1520 [&input, &mpi]<storm::dd::DdType DD, typename VT>() { verifyWithAbstractionRefinementEngine<DD, VT>(input, mpi); });
1521 } else if (mpi.engine == storm::utility::Engine::Exploration) {
1522 applyValueType(mpi.verificationValueType, [&input, &mpi]<typename VT>() { verifyWithExplorationEngine<VT>(input, mpi); });
1523 } else {
1524 std::shared_ptr<storm::models::ModelBase> model = buildPreprocessExportModel(input, mpi);
1525 if (model) {
1526 if (counterexampleSettings.isCounterexampleSet()) {
1527 castAndApply(model, [&input](auto const& m) { generateCounterexamples(m, input); });
1528 } else {
1529 castAndApply(model, [&input, &mpi](auto const& m) { verifyModel(m, input, mpi); });
1530 }
1531 }
1532 }
1533}
1534} // namespace cli
1535} // namespace storm
BuilderOptions & setBuildAllLabels(bool newValue=true)
Should all reward models be built? If not set, only required reward models are build.
BuilderOptions & setExplorationChecks(bool newValue=true)
Should extra checks be performed during exploration.
BuilderOptions & setAddOutOfBoundsState(bool newValue=true)
Should a state for out of bounds be constructed.
BuilderOptions & setReservedBitsForUnboundedVariables(uint64_t value)
Sets the number of bits that will be reserved for unbounded integer variables.
BuilderOptions & setBuildChoiceLabels(bool newValue=true)
Should the choice labels be built?
BuilderOptions & setBuildAllRewardModels(bool newValue=true)
Should all reward models be built? If not set, only required reward models are build.
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 & setApplyMaximalProgressAssumption(bool newValue=true)
Should the maximal progress assumption be applied when building a Markov Automaton?
BuilderOptions & setBuildObservationValuations(bool newValue=true)
Should a observation valuation mapping be built?
BuilderOptions & setAddOverlappingGuardsLabel(bool newValue=true)
Should a state be labelled for overlapping guards.
This class represents the base class of all exception classes.
virtual const char * what() const noexcept override
Retrieves the message associated with this exception.
This class is responsible for managing a set of typed variables and all expressions using these varia...
std::shared_ptr< storm::logic::Formula const > const & getStatesFormula() const
Definition Property.h:52
storm::modelchecker::FilterType getFilterType() const
Definition Property.h:56
static Model eliminateAutomatically(const Model &model, std::vector< jani::Property > properties, uint64_t locationHeuristic, uint64_t edgesHeuristic)
std::shared_ptr< storm::logic::Formula const > getRawFormula() const
Definition Property.cpp:92
std::string const & getName() const
Get the provided name.
Definition Property.cpp:23
FilterExpression const & getFilter() const
Definition Property.cpp:88
static std::shared_ptr< Formula const > getTrueFormula()
Definition Formula.cpp:213
virtual std::optional< storm::dd::DdType > getDdType() const
Definition ModelBase.cpp:19
This class represents a discrete-time Markov chain.
Definition Dtmc.h:13
This class represents a Markov automaton.
This class represents a (discrete-time) Markov decision process.
Definition Mdp.h:13
Base class for all sparse models.
Definition Model.h:32
Base class for all symbolic models.
Definition Model.h:42
storm::expressions::Expression parseFromString(std::string const &expressionString, bool ignoreError=false) const
Parses an expression from the given string.
void setIdentifierMapping(qi::symbols< char, storm::expressions::Expression > const *identifiers_)
Sets an identifier mapping that is used to determine valid variables in the expression.
storm::jani::Model toJani(bool allVariablesGlobal=true, std::string suffix="") const
Converts the PRISM model into an equivalent JANI model.
Definition Program.cpp:2340
This class represents the settings for the abstraction procedures.
std::string getInjectedRefinementPredicates() const
Retrieves a string containing refinement predicates to inject (if there are any).
std::string getConstraintString() const
Retrieves the string that specifies additional constraints.
This class represents the bisimulation settings.
storm::dd::bisimulation::QuotientFormat getQuotientFormat() const
Retrieves the format in which the quotient is to be extracted.
storm::dd::bisimulation::SignatureMode getSignatureMode() const
Retrieves the mode to compute signatures.
bool isQuotientFormatSetFromDefaultValue() const
Retrieves whether the format in which the quotient is to be extracted has been set from its default v...
bool isWeakBisimulationSet() const
Retrieves whether weak bisimulation is to be used.
bool isBuildChoiceLabelsSet() const
Retrieves whether the choice labels should be build.
This class represents the markov chain settings.
Definition IOSettings.h:19
bool isJaniPropertiesSet() const
Retrieves whether the jani-property option was set.
std::string getExplicitIMCAFilename() const
Retrieves the name of the file that contains the model in the IMCA format.
bool areJaniPropertiesSelected() const
Retrieves whether one or more jani-properties have been selected.
std::string getChoiceLabelingFilename() const
Retrieves the name of the file that contains the choice labeling if the model was given using the exp...
bool isStateRewardsSet() const
Retrieves whether the state reward option was set.
std::string getProperty() const
Retrieves the property specified with the property option.
std::string getJaniInputFilename() const
Retrieves the name of the file that contains the JANI model specification if the model was given usin...
bool isChoiceLabelingSet() const
Retrieves whether the choice labeling option was set.
bool isPrismOrJaniInputSet() const
Retrieves whether the JANI or PRISM input option was set.
std::string getPropertyFilter() const
Retrieves the property filter.
std::string getPrismInputFilename() const
Retrieves the name of the file that contains the PRISM model specification if the model was given usi...
bool isExplicitDRNSet() const
Retrieves whether the explicit option with DRN was set.
std::string getExplicitDRNFilename() const
Retrieves the name of the file that contains the model in the DRN format.
std::string getLabelingFilename() const
Retrieves the name of the file that contains the state labeling if the model was given using the expl...
boost::optional< std::vector< std::string > > getQvbsPropertyFilter() const
Retrieves the selected property names.
std::string getStateRewardsFilename() const
Retrieves the name of the file that contains the state rewards if the model was given using the expli...
std::string getTransitionRewardsFilename() const
Retrieves the name of the file that contains the transition rewards if the model was given using the ...
bool isPropertySet() const
Retrieves whether the property option was set.
std::string getQvbsModelName() const
Retrieves the specified model (short-)name of the QVBS.
std::vector< std::string > getSelectedJaniProperties() const
std::string getTransitionFilename() const
Retrieves the name of the file that contains the transitions if the model was given using the explici...
uint64_t getQvbsInstanceIndex() const
Retrieves the selected model instance (file + open parameters of the model)
bool isExplicitIMCASet() const
Retrieves whether the explicit option with IMCA was set.
bool isPrismInputSet() const
Retrieves whether the PRISM language option was set.
bool isTransitionRewardsSet() const
Retrieves whether the transition reward option was set.
bool isExplicitSet() const
Retrieves whether the explicit option was set.
This class provides easy access to a benchmark of the Quantitative Verification Benchmark Set http://...
Definition Qvbs.h:17
std::string const & getJaniFile(uint64_t instanceIndex=0) const
Definition Qvbs.cpp:107
std::string getInfo(uint64_t instanceIndex=0, boost::optional< std::vector< std::string > > propertyFilter=boost::none) const
Definition Qvbs.cpp:118
std::string const & getConstantDefinition(uint64_t instanceIndex=0) const
Definition Qvbs.cpp:112
storm::jani::Model const & asJaniModel() const
Transformer for eliminating chains of non-Markovian states (instantaneous path fragment leading to th...
storm::utility::Engine getEngine() const
Retrieve "good" settings after calling predict.
void predict(storm::jani::Model const &model, storm::jani::Property const &property)
Predicts "good" settings for the provided model checking query.
A class that provides convenience operations to display run times.
Definition Stopwatch.h:14
void stop()
Stop stopwatch and add measured time to total time.
Definition Stopwatch.cpp:42
#define STORM_LOG_INFO(message)
Definition logging.h:24
#define STORM_LOG_WARN(message)
Definition logging.h:25
#define STORM_LOG_TRACE(message)
Definition logging.h:12
#define STORM_LOG_ERROR(message)
Definition logging.h:26
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
#define STORM_PRINT_AND_LOG(message)
Definition macros.h:68
#define STORM_PRINT(message)
Define the macros that print information and optionally also log it.
Definition macros.h:62
void exportScheduler(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, storm::storage::Scheduler< ValueType > const &scheduler, std::string const &filename)
Definition export.h:66
void exportSymbolicModelAsDot(std::shared_ptr< storm::models::symbolic::Model< Type, ValueType > > const &model, std::string const &filename)
Definition export.h:61
storm::prism::Program parseProgram(std::string const &filename, bool prismCompatibility, bool simplify)
std::shared_ptr< storm::models::sparse::Model< ValueType > > permuteModelStates(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, storm::utility::permutation::OrderKind order, std::optional< uint64_t > seed=std::nullopt)
Permutes the order of the states of the model according to the given order.
std::shared_ptr< storm::counterexamples::Counterexample > computeHighLevelCounterexampleMilp(storm::storage::SymbolicModelDescription const &symbolicModel, std::shared_ptr< storm::models::sparse::Mdp< double > > mdp, std::shared_ptr< storm::logic::Formula const > const &formula)
std::pair< std::shared_ptr< storm::models::sparse::Model< ValueType > >, std::vector< std::shared_ptr< storm::logic::Formula const > > > eliminateNonMarkovianChains(std::shared_ptr< storm::models::sparse::MarkovAutomaton< ValueType > > const &ma, std::vector< std::shared_ptr< storm::logic::Formula const > > const &formulas, storm::transformer::EliminationLabelBehavior labelBehavior)
Eliminates chains of non-Markovian states from a given Markov Automaton.
storm::jani::Property createMultiObjectiveProperty(std::vector< storm::jani::Property > const &properties)
std::pair< storm::jani::Model, std::vector< storm::jani::Property > > parseJaniModel(std::string const &filename, boost::optional< std::vector< std::string > > const &propertyFilter)
void exportJaniModelAsDot(storm::jani::Model const &model, std::string const &filename)
Definition export.cpp:7
std::vector< storm::jani::Property > parseProperties(storm::parser::FormulaParser &formulaParser, std::string const &inputString, boost::optional< std::set< std::string > > const &propertyFilter)
std::shared_ptr< storm::models::sparse::Model< ValueType > > transformSymbolicToSparseModel(std::shared_ptr< storm::models::symbolic::Model< Type, ValueType > > const &symbolicModel, std::vector< std::shared_ptr< storm::logic::Formula const > > const &formulas=std::vector< std::shared_ptr< storm::logic::Formula const > >())
Transforms the given symbolic model to a sparse model.
std::pair< std::shared_ptr< storm::models::sparse::Model< ValueType > >, std::vector< std::shared_ptr< storm::logic::Formula const > > > transformContinuousToDiscreteTimeSparseModel(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, std::vector< std::shared_ptr< storm::logic::Formula const > > const &formulas)
Transforms the given continuous model to a discrete time model.
void exportSymbolicModelAsDrdd(std::shared_ptr< storm::models::symbolic::Model< Type, ValueType > > const &model, std::string const &filename)
Definition export.h:40
std::shared_ptr< storm::counterexamples::Counterexample > computeHighLevelCounterexampleMaxSmt(storm::storage::SymbolicModelDescription const &symbolicModel, std::shared_ptr< storm::models::sparse::Model< double > > model, std::shared_ptr< storm::logic::Formula const > const &formula)
std::vector< storm::jani::Property > parsePropertiesForSymbolicModelDescription(std::string const &inputString, storm::storage::SymbolicModelDescription const &modelDescription, boost::optional< std::set< std::string > > const &propertyFilter)
std::vector< std::shared_ptr< storm::logic::Formula const > > extractFormulasFromProperties(std::vector< storm::jani::Property > const &properties)
void simplifyJaniModel(storm::jani::Model &model, std::vector< storm::jani::Property > &properties, storm::jani::ModelFeatures const &supportedFeatures)
boost::optional< std::set< std::string > > parsePropertyFilter(std::string const &propertyFilter)
storm::jani::ModelFeatures getSupportedJaniFeatures(storm::builder::BuilderType const &builderType)
Definition builder.h:31
void exportSparseModelAsDrn(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, std::string const &filename, std::vector< std::string > const &parameterNames={}, bool allowPlaceholders=true)
Definition export.h:29
void exportCheckResultToJson(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, std::unique_ptr< storm::modelchecker::CheckResult > const &checkResult, std::string const &filename)
Definition export.h:113
std::shared_ptr< storm::counterexamples::Counterexample > computeKShortestPathCounterexample(std::shared_ptr< storm::models::sparse::Model< double > > model, std::shared_ptr< storm::logic::Formula const > const &formula, size_t maxK)
void exportSparseModelAsJson(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, std::string const &filename)
Definition export.h:53
void exportSparseModelAsDot(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, std::string const &filename, size_t maxWidth=30)
Definition export.h:45
void exportParetoScheduler(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, std::vector< PointType > const &points, std::vector< storm::storage::Scheduler< ValueType > > const &schedulers, std::string const &baseFilenameStr)
Definition export.h:80
std::vector< storm::jani::Property > substituteConstantsInProperties(std::vector< storm::jani::Property > const &properties, std::map< storm::expressions::Variable, storm::expressions::Expression > const &substitution)
void exportModel(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, SymbolicInput const &input)
void exportSymbolicInput(SymbolicInput const &input)
void parseSymbolicModelDescription(storm::settings::modules::IOSettings const &ioSettings, SymbolicInput &input)
void verifyWithAbstractionRefinementEngine(SymbolicInput const &input, ModelProcessingInformation const &mpi)
std::shared_ptr< storm::models::ModelBase > buildModelExplicit(storm::settings::modules::IOSettings const &ioSettings, storm::settings::modules::BuildSettings const &buildSettings)
std::enable_if< DdType==storm::dd::DdType::CUDD &&!std::is_same< ValueType, double >::value, void >::type verifySymbolicModel(std::shared_ptr< storm::models::ModelBase > const &, SymbolicInput const &, ModelProcessingInformation const &)
void verifyModel(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &sparseModel, SymbolicInput const &input, ModelProcessingInformation const &mpi)
auto castAndApply(std::shared_ptr< storm::models::ModelBase > const &model, auto const &callback)
SymbolicInput parseSymbolicInputQvbs(storm::settings::modules::IOSettings const &ioSettings)
void getModelProcessingInformationAutomatic(SymbolicInput const &input, ModelProcessingInformation &mpi)
void verifyWithExplorationEngine(SymbolicInput const &input, ModelProcessingInformation const &mpi)
std::shared_ptr< storm::models::sparse::Model< ValueType > > preprocessSparseModelBisimulation(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, SymbolicInput const &input, storm::settings::modules::BisimulationSettings const &bisimulationSettings, bool graphPreserving=true)
void printResult(std::unique_ptr< storm::modelchecker::CheckResult > const &result, storm::logic::Formula const &filterStatesFormula, storm::modelchecker::FilterType const &filterType, storm::utility::Stopwatch *watch=nullptr)
auto applyValueType(ModelProcessingInformation::ValueType vt, auto const &callback)
std::shared_ptr< storm::models::ModelBase > buildPreprocessExportModel(SymbolicInput const &input, ModelProcessingInformation const &mpi)
void verifyProperties(SymbolicInput const &input, VerificationCallbackType const &verificationCallback, PostprocessingCallbackType const &postprocessingCallback=PostprocessingIdentity())
Verifies all (potentially preprocessed) properties given in input.
std::vector< storm::expressions::Expression > parseConstraints(storm::expressions::ExpressionManager const &expressionManager, std::string const &constraintsString)
std::vector< std::vector< storm::expressions::Expression > > parseInjectedRefinementPredicates(storm::expressions::ExpressionManager const &expressionManager, std::string const &refinementPredicatesString)
SymbolicInput parseSymbolicInput()
void verifyWithDdEngine(std::shared_ptr< storm::models::symbolic::Model< DdType, ValueType > > const &symbolicModel, SymbolicInput const &input, ModelProcessingInformation const &mpi)
std::function< std::unique_ptr< storm::modelchecker::CheckResult >(std::shared_ptr< storm::logic::Formula const > const &formula, std::shared_ptr< storm::logic::Formula const > const &states)> VerificationCallbackType
std::shared_ptr< storm::models::ModelBase > buildModelSparse(SymbolicInput const &input, storm::builder::BuilderOptions const &options)
std::enable_if< DdType!=storm::dd::DdType::Sylvan &&!std::is_same< ValueType, double >::value, std::shared_ptr< storm::models::Model< ValueType > > >::type preprocessDdMarkovAutomaton(std::shared_ptr< storm::models::symbolic::Model< DdType, ValueType > > const &model)
std::shared_ptr< storm::models::sparse::Model< ValueType > > preprocessSparseMarkovAutomaton(std::shared_ptr< storm::models::sparse::MarkovAutomaton< ValueType > > const &model)
void printFilteredResult(std::unique_ptr< storm::modelchecker::CheckResult > const &result, storm::modelchecker::FilterType ft)
void computeStateValues(std::string const &description, std::function< std::unique_ptr< storm::modelchecker::CheckResult >()> const &computationCallback, SymbolicInput const &input, VerificationCallbackType const &verificationCallback, PostprocessingCallbackType const &postprocessingCallback=PostprocessingIdentity())
Computes values for each state (such as the steady-state probability distribution).
void printCounterexample(std::shared_ptr< storm::counterexamples::Counterexample > const &counterexample, storm::utility::Stopwatch *watch=nullptr)
std::pair< SymbolicInput, ModelProcessingInformation > preprocessSymbolicInput(SymbolicInput const &input)
std::shared_ptr< storm::models::ModelBase > buildModel(SymbolicInput const &input, storm::settings::modules::IOSettings const &ioSettings, ModelProcessingInformation const &mpi)
void printModelCheckingProperty(storm::jani::Property const &property)
void parseProperties(storm::settings::modules::IOSettings const &ioSettings, SymbolicInput &input, boost::optional< std::set< std::string > > const &propertyFilter)
void verifyWithHybridEngine(std::shared_ptr< storm::models::symbolic::Model< DdType, ValueType > > const &symbolicModel, SymbolicInput const &input, ModelProcessingInformation const &mpi)
ModelProcessingInformation getModelProcessingInformation(SymbolicInput const &input, std::shared_ptr< SymbolicInput > const &transformedJaniInput=nullptr)
Sets the model processing information based on the given input.
void printComputingCounterexample(storm::jani::Property const &property)
std::shared_ptr< storm::models::Model< ExportValueType > > preprocessDdModelBisimulation(std::shared_ptr< storm::models::symbolic::Model< DdType, ValueType > > const &model, SymbolicInput const &input, storm::settings::modules::BisimulationSettings const &bisimulationSettings, ModelProcessingInformation const &mpi)
auto applyDdLibValueType(storm::dd::DdType dd, ModelProcessingInformation::ValueType vt, auto const &callback)
std::function< void(std::unique_ptr< storm::modelchecker::CheckResult > const &)> PostprocessingCallbackType
std::shared_ptr< storm::models::ModelBase > buildPreprocessModel(SymbolicInput const &input, ModelProcessingInformation const &mpi)
storm::builder::BuilderOptions createBuildOptionsSparseFromSettings(SymbolicInput const &input)
void processInput(SymbolicInput const &input, ModelProcessingInformation const &mpi)
void ensureNoUndefinedPropertyConstants(std::vector< storm::jani::Property > const &properties)
void generateCounterexamples(std::shared_ptr< ModelType > const &, SymbolicInput const &)
std::vector< std::shared_ptr< storm::logic::Formula const > > createFormulasToRespect(std::vector< storm::jani::Property > const &properties)
std::pair< std::shared_ptr< storm::models::ModelBase >, bool > preprocessModel(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, SymbolicInput const &input, ModelProcessingInformation const &mpi)
std::shared_ptr< storm::models::ModelBase > buildModelDd(SymbolicInput const &input)
std::pair< std::shared_ptr< storm::models::ModelBase >, bool > preprocessDdModelImpl(std::shared_ptr< storm::models::symbolic::Model< DdType, ValueType > > const &model, SymbolicInput const &input, ModelProcessingInformation const &mpi)
std::unique_ptr< storm::modelchecker::CheckResult > verifyProperty(std::shared_ptr< storm::logic::Formula const > const &formula, std::shared_ptr< storm::logic::Formula const > const &statesFilter, VerificationCallbackType const &verificationCallback)
Verifies the given formula plus a filter formula to identify relevant states and warns the user in ca...
std::string toString(ModelExportFormat const &input)
SettingsManager const & manager()
Retrieves the settings manager.
std::string orderKindtoString(OrderKind order)
Converts the given order to a string.
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
bool isConstant(ValueType const &)
Definition constants.cpp:67
bool canHandle< storm::RationalFunction >(storm::utility::Engine const &engine, storm::storage::SymbolicModelDescription::ModelType const &modelType, storm::modelchecker::CheckTask< storm::logic::Formula, storm::RationalFunction > const &checkTask)
Definition Engine.cpp:198
Engine
An enumeration of all engines.
Definition Engine.h:31
template bool canHandle< storm::RationalNumber >(storm::utility::Engine const &, std::vector< storm::jani::Property > const &, storm::storage::SymbolicModelDescription const &)
template bool canHandle< double >(storm::utility::Engine const &, std::vector< storm::jani::Property > const &, storm::storage::SymbolicModelDescription const &)
storm::builder::BuilderType getBuilderType(Engine const &engine)
Returns the builder type used for the given engine.
Definition Engine.cpp:80
typename detail::IntervalMetaProgrammingHelper< ValueType >::BaseType IntervalBaseType
Helper to access the type in which interval boundaries are stored.
void operator()(std::unique_ptr< storm::modelchecker::CheckResult > const &)
std::vector< storm::jani::Property > properties
boost::optional< storm::storage::SymbolicModelDescription > model
boost::optional< std::vector< storm::jani::Property > > preprocessedProperties