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