Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
model-handling-main-cli.h
Go to the documentation of this file.
1#pragma once
2
3#include <filesystem>
4#include <optional>
5#include <sstream>
6
9
20
21namespace storm {
22namespace cli {
23
24inline void exportSymbolicInput(SymbolicInput const& input) {
26 if (input.model && input.model.get().isJaniModel()) {
27 storm::storage::SymbolicModelDescription const& model = input.model.get();
28 if (ioSettings.isExportJaniDotSet()) {
29 storm::api::exportJaniModelAsDot(model.asJaniModel(), ioSettings.getExportJaniDotFilename());
30 }
31 }
32}
33
35 STORM_PRINT("Computing counterexample for property " << *property.getRawFormula() << " ...\n");
36}
37
38inline void printCounterexample(std::shared_ptr<storm::counterexamples::Counterexample> const& counterexample, storm::utility::Stopwatch* watch = nullptr) {
39 if (counterexample) {
40 STORM_PRINT(*counterexample << '\n');
41 if (watch) {
42 STORM_PRINT("Time for computation: " << *watch << ".\n");
43 }
44 } else {
45 STORM_PRINT(" failed.\n");
46 }
47}
48
49template<typename ModelType>
50 requires(!std::derived_from<ModelType, storm::models::sparse::Model<double>>)
51inline void generateCounterexamples(std::shared_ptr<ModelType> const&, SymbolicInput const&, ModelProcessingInformation const&) {
52 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Counterexample generation is not supported for this data-type.");
53}
54
55template<typename ModelType>
56 requires(std::derived_from<ModelType, storm::models::sparse::Model<double>>)
57inline void generateCounterexamples(std::shared_ptr<ModelType> const& sparseModel, SymbolicInput const& input, ModelProcessingInformation const& mpi) {
58 using ValueType = typename ModelType::ValueType;
59
60 for (auto& rewModel : sparseModel->getRewardModels()) {
61 rewModel.second.reduceToStateBasedRewards(sparseModel->getTransitionMatrix(), true);
62 }
63
64 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Dtmc) || sparseModel->isOfType(storm::models::ModelType::Mdp),
65 storm::exceptions::NotSupportedException, "Counterexample is currently only supported for discrete-time models.");
66
68 if (counterexampleSettings.isMinimalCommandSetGenerationSet()) {
69 bool useMilp = counterexampleSettings.isUseMilpBasedMinimalCommandSetGenerationSet();
71 maxSmtOptions.encodeReachability = counterexampleSettings.isEncodeReachabilitySet();
72 maxSmtOptions.useDynamicConstraints = counterexampleSettings.isUseDynamicConstraintsSet();
73 for (auto const& property : input.properties) {
74 std::shared_ptr<storm::counterexamples::Counterexample> counterexample;
76 storm::utility::Stopwatch watch(true);
77 if (useMilp) {
78 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException,
79 "Counterexample generation using MILP is currently only supported for MDPs.");
80 counterexample = storm::api::computeHighLevelCounterexampleMilp(mpi.env, input.model.get(),
81 sparseModel->template as<storm::models::sparse::Mdp<ValueType>>(),
82 property.getRawFormula(), counterexampleSettings.isUseSchedulerCutsSet());
83 } else {
84 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Dtmc) || sparseModel->isOfType(storm::models::ModelType::Mdp),
85 storm::exceptions::NotSupportedException,
86 "Counterexample generation using MaxSAT is currently only supported for discrete-time models.");
87
88 if (sparseModel->isOfType(storm::models::ModelType::Dtmc)) {
89 counterexample = storm::api::computeHighLevelCounterexampleMaxSmt(mpi.env, input.model.get(),
90 sparseModel->template as<storm::models::sparse::Dtmc<ValueType>>(),
91 property.getRawFormula(), maxSmtOptions);
92 } else {
94 mpi.env, input.model.get(), sparseModel->template as<storm::models::sparse::Mdp<ValueType>>(), property.getRawFormula(), maxSmtOptions);
95 }
96 }
97 watch.stop();
98 printCounterexample(counterexample, &watch);
99 }
100 } else if (counterexampleSettings.isShortestPathGenerationSet()) {
101 for (auto const& property : input.properties) {
102 std::shared_ptr<storm::counterexamples::Counterexample> counterexample;
104 storm::utility::Stopwatch watch(true);
105 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Dtmc), storm::exceptions::NotSupportedException,
106 "Counterexample generation using shortest paths is currently only supported for DTMCs.");
108 property.getRawFormula(), counterexampleSettings.getShortestPathMaxK());
109 watch.stop();
110 printCounterexample(counterexample, &watch);
111 }
112 } else {
113 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The selected counterexample formalism is unsupported.");
114 }
115}
116
117template<typename ValueType>
119void printFilteredResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::modelchecker::FilterType ft) {
120 if (result->isQuantitative()) {
122 STORM_PRINT(*result);
123 } else {
124 switch (ft) {
129 break;
132 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Outputting states is not supported.");
133 break;
137 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Filter type only defined for qualitative results.");
138 break;
139 default:
140 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Unhandled filter type.");
141 }
142 auto const aggregate = result->asQuantitativeCheckResult<ValueType>().aggregate(ft);
143 auto const printSide = [](std::optional<storm::utility::ExtendedValueType<ValueType>> const& value, bool approximate) {
144 if (!value) {
145 STORM_PRINT("?");
146 } else if (storm::utility::isInfinity(*value)) {
147 STORM_PRINT("inf");
148 } else if (approximate) {
150 } else {
151 STORM_PRINT(*value);
152 }
153 };
154 // Only an exact value type has a decimal approximation to add, and a rational function has none to give.
155 bool const approximates =
157 printSide(aggregate.value, false);
158 if (approximates) {
159 STORM_PRINT(" (approx. ");
160 printSide(aggregate.value, true);
161 STORM_PRINT(")");
162 }
163 // An aggregate of an enclosure encloses the aggregate, so report it in the same shape as the values do.
164 if (aggregate.hasLower() && aggregate.hasUpper() && *aggregate.lower == *aggregate.upper) {
165 STORM_PRINT(". Exact solution.");
166 } else if (aggregate.hasLower() || aggregate.hasUpper()) {
167 STORM_PRINT(". Solution bounds: [");
168 printSide(aggregate.lower, false);
169 STORM_PRINT(", ");
170 printSide(aggregate.upper, false);
171 STORM_PRINT("]");
172 if (approximates) {
173 STORM_PRINT(" (approx. [");
174 printSide(aggregate.lower, true);
175 STORM_PRINT(", ");
176 printSide(aggregate.upper, true);
177 STORM_PRINT("])");
178 }
179 STORM_PRINT(".");
180 }
181 }
182 } else {
183 switch (ft) {
185 STORM_PRINT(*result << '\n');
186 break;
188 STORM_PRINT(result->asQualitativeCheckResult().existsTrue());
189 break;
191 STORM_PRINT(result->asQualitativeCheckResult().forallTrue());
192 break;
194 STORM_PRINT(result->asQualitativeCheckResult().count());
195 break;
198 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Outputting states is not supported.");
199 break;
204 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Filter type only defined for quantitative results.");
205 }
206 }
207 STORM_PRINT('\n');
208}
209
210template<typename ValueType>
212void printResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::logic::Formula const& filterStatesFormula,
213 storm::modelchecker::FilterType const& filterType, storm::utility::Stopwatch* watch = nullptr) {
214 if (result) {
215 std::stringstream ss;
216 ss << "'" << filterStatesFormula << "'";
217 STORM_PRINT((storm::utility::resources::isTerminate() ? "Result till abort" : "Result")
218 << " (for " << (filterStatesFormula.isInitialFormula() ? "initial" : ss.str()) << " states): ");
219 printFilteredResult<ValueType>(result, filterType);
220 if (watch) {
221 STORM_PRINT("Time for model checking: " << *watch << ".\n");
222 }
223 } else {
224 STORM_LOG_ERROR("Property is unsupported by selected engine/settings.\n");
225 }
226}
227
228template<typename ValueType>
229void printResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::jani::Property const& property,
230 storm::utility::Stopwatch* watch = nullptr) {
231 printResult<ValueType>(result, *property.getFilter().getStatesFormula(), property.getFilter().getFilterType(), watch);
232}
233
234using VerificationCallbackType = std::function<std::unique_ptr<storm::modelchecker::CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula,
235 std::shared_ptr<storm::logic::Formula const> const& states)>;
236using PostprocessingCallbackType = std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)>;
237
239 void operator()(std::unique_ptr<storm::modelchecker::CheckResult> const&) {
240 // Intentionally left empty.
241 }
242};
243
250template<typename ValueType>
251std::unique_ptr<storm::modelchecker::CheckResult> verifyProperty(std::shared_ptr<storm::logic::Formula const> const& formula,
252 std::shared_ptr<storm::logic::Formula const> const& statesFilter,
253 VerificationCallbackType const& verificationCallback) {
255
256 try {
257 if constexpr (storm::IsIntervalType<ValueType>) {
258 STORM_LOG_ASSERT(!transformationSettings.isChainEliminationSet() && !transformationSettings.isToNondeterministicModelSet(),
259 "Unsupported transformation has been invoked.");
260 return verificationCallback(formula, statesFilter);
261 }
262 if (transformationSettings.isChainEliminationSet() && !storm::transformer::NonMarkovianChainTransformer<ValueType>::preservesFormula(*formula)) {
263 STORM_LOG_WARN("Property is not preserved by elimination of non-markovian states.");
264 } else if (transformationSettings.isToDiscreteTimeModelSet()) {
266 auto transformedStatesFilter = storm::api::checkAndTransformContinuousToDiscreteTimeFormula<ValueType>(*statesFilter);
267 if (transformedFormula && transformedStatesFilter) {
268 // invoke verification algorithm on transformed formulas
269 return verificationCallback(transformedFormula, transformedStatesFilter);
270 } else {
271 STORM_LOG_WARN("Property is not preserved by transformation to discrete time model.");
272 }
273 } else {
274 // invoke verification algorithm on given formulas
275 return verificationCallback(formula, statesFilter);
276 }
277 } catch (storm::exceptions::BaseException const& ex) {
278 STORM_LOG_WARN("Cannot handle property: " << ex.what());
279 }
280 return nullptr;
281}
282
289template<typename ValueType>
290void verifyProperties(SymbolicInput const& input, VerificationCallbackType const& verificationCallback,
291 PostprocessingCallbackType const& postprocessingCallback = PostprocessingIdentity()) {
292 auto const& properties = input.preprocessedProperties ? input.preprocessedProperties.get() : input.properties;
293 for (auto const& property : properties) {
295 storm::utility::Stopwatch watch(true);
296 auto result = verifyProperty<ValueType>(property.getRawFormula(), property.getFilter().getStatesFormula(), verificationCallback);
297 watch.stop();
298 if (result) {
299 postprocessingCallback(result);
300 }
301 printResult<storm::IntervalBaseType<ValueType>>(result, property, &watch);
302 }
303}
304
314template<typename ValueType>
315void computeStateValues(std::string const& description, std::function<std::unique_ptr<storm::modelchecker::CheckResult>()> const& computationCallback,
316 SymbolicInput const& input, VerificationCallbackType const& verificationCallback,
317 PostprocessingCallbackType const& postprocessingCallback = PostprocessingIdentity()) {
318 // First compute the state values for all the states by invoking the computationCallback
319 storm::utility::Stopwatch watch(true);
320 STORM_PRINT("\nComputing " << description << " ...\n");
321 std::unique_ptr<storm::modelchecker::CheckResult> result;
322 try {
323 result = computationCallback();
324 } catch (storm::exceptions::BaseException const& ex) {
325 STORM_LOG_ERROR("Cannot compute " << description << ": " << ex.what());
326 }
327 if (!result) {
328 STORM_LOG_ERROR("Computation had no result.");
329 return;
330 }
331 // Now process the (potentially filtered) result
332 if (input.properties.empty()) {
333 // Do not apply any filtering, consider result for *all* states
334 postprocessingCallback(result);
336 } else {
337 // Each property identifies a subset of states to which we restrict (aka filter) the state-value result to
338 auto const& properties = input.preprocessedProperties ? input.preprocessedProperties.get() : input.properties;
339 for (uint64_t propertyIndex = 0; propertyIndex < properties.size(); ++propertyIndex) {
340 auto const& property = properties[propertyIndex];
341 // As the property serves as filter, it should (a) be qualitative and should (b) not consider a filter itself.
342 if (!property.getRawFormula()->hasQualitativeResult()) {
343 STORM_LOG_ERROR("Property '" << *property.getRawFormula()
344 << "' can not be used for filtering states as it does not have a qualitative result.");
345 continue;
346 }
347
348 // Invoke verification algorithm on filtering property
349 auto propertyFilter = verifyProperty<ValueType>(property.getRawFormula(), storm::logic::Formula::getTrueFormula(), verificationCallback);
350
351 if (propertyFilter) {
352 // Filter and process result
353 std::unique_ptr<storm::modelchecker::CheckResult> filteredResult = result->clone();
354 filteredResult->filter(propertyFilter->asQualitativeCheckResult());
355 postprocessingCallback(filteredResult);
356 printResult<ValueType>(filteredResult, *property.getRawFormula(), property.getFilter().getFilterType(),
357 propertyIndex == properties.size() - 1 ? &watch : nullptr);
358 }
359 }
360 }
361}
362
363inline std::vector<storm::expressions::Expression> parseConstraints(storm::expressions::ExpressionManager const& expressionManager,
364 std::string const& constraintsString) {
365 std::vector<storm::expressions::Expression> constraints;
366
367 std::vector<std::string> constraintsAsStrings;
368 boost::split(constraintsAsStrings, constraintsString, boost::is_any_of(","));
369
370 storm::parser::ExpressionParser expressionParser(expressionManager);
371 std::unordered_map<std::string, storm::expressions::Expression> variableMapping;
372 for (auto const& variableTypePair : expressionManager) {
373 variableMapping[variableTypePair.first.getName()] = variableTypePair.first;
374 }
375 expressionParser.setIdentifierMapping(variableMapping);
376
377 for (auto const& constraintString : constraintsAsStrings) {
378 if (constraintString.empty()) {
379 continue;
380 }
381
382 storm::expressions::Expression constraint = expressionParser.parseFromString(constraintString);
383 STORM_LOG_TRACE("Adding special (user-provided) constraint " << constraint << ".");
384 constraints.emplace_back(constraint);
385 }
386
387 return constraints;
388}
389
390inline std::vector<std::vector<storm::expressions::Expression>> parseInjectedRefinementPredicates(
391 storm::expressions::ExpressionManager const& expressionManager, std::string const& refinementPredicatesString) {
392 std::vector<std::vector<storm::expressions::Expression>> injectedRefinementPredicates;
393
394 storm::parser::ExpressionParser expressionParser(expressionManager);
395 std::unordered_map<std::string, storm::expressions::Expression> variableMapping;
396 for (auto const& variableTypePair : expressionManager) {
397 variableMapping[variableTypePair.first.getName()] = variableTypePair.first;
398 }
399 expressionParser.setIdentifierMapping(variableMapping);
400
401 std::vector<std::string> predicateGroupsAsStrings;
402 boost::split(predicateGroupsAsStrings, refinementPredicatesString, boost::is_any_of(";"));
403
404 if (!predicateGroupsAsStrings.empty()) {
405 for (auto const& predicateGroupString : predicateGroupsAsStrings) {
406 if (predicateGroupString.empty()) {
407 continue;
408 }
409
410 std::vector<std::string> predicatesAsStrings;
411 boost::split(predicatesAsStrings, predicateGroupString, boost::is_any_of(":"));
412
413 if (!predicatesAsStrings.empty()) {
414 injectedRefinementPredicates.emplace_back();
415 for (auto const& predicateString : predicatesAsStrings) {
416 storm::expressions::Expression predicate = expressionParser.parseFromString(predicateString);
417 STORM_LOG_TRACE("Adding special (user-provided) refinement predicate " << predicateString << ".");
418 injectedRefinementPredicates.back().emplace_back(predicate);
419 }
420
421 STORM_LOG_THROW(!injectedRefinementPredicates.back().empty(), storm::exceptions::InvalidArgumentException,
422 "Expecting non-empty list of predicates to inject for each (mentioned) refinement step.");
423
424 // Finally reverse the list, because we take the predicates from the back.
425 std::reverse(injectedRefinementPredicates.back().begin(), injectedRefinementPredicates.back().end());
426 }
427 }
428
429 // Finally reverse the list, because we take the predicates from the back.
430 std::reverse(injectedRefinementPredicates.begin(), injectedRefinementPredicates.end());
431 }
432
433 return injectedRefinementPredicates;
434}
435
437 storm::expressions::ExpressionManager const* expressionManager = nullptr) {
440 if (expressionManager != nullptr) {
441 options.constraints = parseConstraints(*expressionManager, settings.getConstraintString());
442 options.injectedRefinementPredicates = parseInjectedRefinementPredicates(*expressionManager, settings.getInjectedRefinementPredicates());
443 }
444 options.restrictToRelevantStates = settings.isRestrictToRelevantStatesSet();
445 options.restrictToValidBlocks = settings.getValidBlockMode() == storm::settings::modules::AbstractionSettings::ValidBlockMode::BlockEnumeration;
446 options.useDecomposition = settings.isUseDecompositionSet();
447 options.useInterpolation = settings.isUseInterpolationSet();
448 options.splitMode = settings.getSplitMode();
449 options.pivotSelectionHeuristic = settings.getPivotSelectionHeuristic();
450 options.rankRefinementPredicates = settings.isRankRefinementPredicatesSet();
451 options.useEagerRefinement = settings.isUseEagerRefinementSet();
452 options.addAllGuards = settings.isAddAllGuardsSet();
453 options.addAllInitialExpressions = settings.isAddAllInitialExpressionsSet();
454 options.precision = settings.getPrecision();
455 options.relativeTerminationCriterion = settings.getRelativeTerminationCriterion();
456 options.solveMode = settings.getSolveMode();
457 options.reuseMode = settings.getReuseMode();
458 options.maximalNumberOfAbstractions = settings.getMaximalAbstractionCount();
459 options.fixPlayer1Strategy = settings.isFixPlayer1StrategySet();
460 options.fixPlayer2Strategy = settings.isFixPlayer2StrategySet();
461 options.debug = settings.isDebugSet();
462 return options;
463}
464
465template<storm::dd::DdType DdType, typename ValueType>
467 STORM_LOG_ASSERT(input.model, "Expected symbolic model description.");
469
470 verifyProperties<ValueType>(input, [&input, &options, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula,
471 std::shared_ptr<storm::logic::Formula const> const& states) {
472 STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Abstraction-refinement can only filter initial states.");
474 storm::api::createTask<ValueType>(formula, true), options);
475 });
476}
477
478template<typename ValueType>
480 STORM_LOG_ASSERT(input.model, "Expected symbolic model description.");
481 STORM_LOG_THROW((std::is_same<ValueType, double>::value), storm::exceptions::NotSupportedException,
482 "Exploration does not support other data-types than floating points.");
484 input, [&input, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
485 STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Exploration can only filter initial states.");
487 });
488}
489
490template<typename ValueType>
491void verifyModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& sparseModel, SymbolicInput const& input,
492 ModelProcessingInformation const& mpi) {
495 auto verificationCallback = [&sparseModel, &ioSettings, &mpi, preferEliminationChecker](std::shared_ptr<storm::logic::Formula const> const& formula,
496 std::shared_ptr<storm::logic::Formula const> const& states) {
497 auto createTask = [&ioSettings](auto const& f, bool onlyInitialStates) {
498 if constexpr (storm::IsIntervalType<ValueType>) {
499 STORM_LOG_THROW(ioSettings.isUncertaintyResolutionModeSet(), storm::exceptions::InvalidSettingsException,
500 "Uncertainty resolution mode required for uncertain (interval) models.");
501 return storm::api::createTask<ValueType>(f, storm::solver::convert(ioSettings.getUncertaintyResolutionMode()), onlyInitialStates);
502 } else {
503 (void)ioSettings; // suppress unused lambda capture warning. [[maybe_unused]] doesn't work for lambda captures.
504 return storm::api::createTask<ValueType>(f, onlyInitialStates);
505 }
506 };
507 bool const filterForInitialStates = states->isInitialFormula();
508 auto task = createTask(formula, filterForInitialStates);
509 if (ioSettings.isExportSchedulerSet()) {
510 task.setProduceSchedulers(true);
511 }
512 std::unique_ptr<storm::modelchecker::CheckResult> result =
514
515 std::unique_ptr<storm::modelchecker::CheckResult> filter;
516 if (filterForInitialStates) {
517 using SolutionType = storm::IntervalBaseType<ValueType>;
518 filter = std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult<SolutionType>>(sparseModel->getInitialStates());
519 } else if (!states->isTrueFormula()) { // No need to apply filter if it is the formula 'true'
520 filter = storm::api::verifyWithSparseEngine<ValueType>(mpi.env, sparseModel, createTask(states, false), preferEliminationChecker);
521 }
522 if (result && filter) {
523 result->filter(filter->asQualitativeCheckResult());
524 }
525 return result;
526 };
527 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.
528 auto postprocessingCallback = [&sparseModel, &ioSettings, &input, &exportCount](std::unique_ptr<storm::modelchecker::CheckResult> const& result) {
529 // Scheduler export
530 STORM_LOG_WARN_COND(!ioSettings.isExportSchedulerSet() || result->hasScheduler(), "Scheduler requested but could not be generated.");
531 if (ioSettings.isExportSchedulerSet() && result->hasScheduler()) {
532 std::filesystem::path schedulerExportPath = ioSettings.getExportSchedulerFilename();
533 if (exportCount > 0) {
534 STORM_LOG_WARN("Prepending " << exportCount << " to scheduler file name for this property because there are multiple properties.");
535 schedulerExportPath.replace_filename(std::to_string(exportCount) + schedulerExportPath.filename().string());
536 }
537 STORM_PRINT_AND_LOG("Exporting scheduler ... ");
538 if (input.model) {
539 STORM_LOG_WARN_COND(sparseModel->hasStateValuations(),
540 "No information of state valuations available. The scheduler output will use internal state ids. You might be "
541 "interested in building the model with state valuations using --buildstateval.");
543 sparseModel->hasChoiceLabeling() || sparseModel->hasChoiceOrigins(),
544 "No symbolic choice information is available. The scheduler output will use internal choice ids. You might be interested in "
545 "building the model with choice labels or choice origins using --buildchoicelab or --buildchoiceorig.");
546 STORM_LOG_WARN_COND(sparseModel->hasChoiceLabeling() && !sparseModel->hasChoiceOrigins(),
547 "Only partial choice information is available. You might want to build the model with choice origins using "
548 "--buildchoicelab or --buildchoiceorig.");
549 }
550 if (result->isExplicitQuantitativeCheckResult()) {
551 if constexpr (storm::IsIntervalType<ValueType>) {
552 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export for interval models is not supported.");
553 } else {
554 storm::api::exportScheduler(sparseModel, result->template asExplicitQuantitativeCheckResult<ValueType>().getScheduler(),
555 schedulerExportPath.string());
556 }
557 } else if (result->isExplicitParetoCurveCheckResult()) {
558 if constexpr (std::is_same_v<ValueType, storm::RationalFunction> || storm::IsIntervalType<ValueType>) {
559 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export for models of this value type is not supported.");
560 } else {
561 auto const& paretoRes = result->template asExplicitParetoCurveCheckResult<ValueType>();
562 storm::api::exportParetoScheduler(sparseModel, paretoRes.getPoints(), paretoRes.getSchedulers(), schedulerExportPath.string());
563 }
564 } else if (result->isExplicitQualitativeCheckResult()) {
565 if constexpr (storm::IsIntervalType<ValueType>) {
566 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export for interval models is not supported.");
567 } else {
568 storm::api::exportScheduler(sparseModel, result->template asExplicitQualitativeCheckResult<ValueType>().getScheduler(),
569 schedulerExportPath.string());
570 }
571 } else {
572 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export not supported for this value type.");
573 }
574 }
575
576 // Result export
577 if (ioSettings.isExportCheckResultSet()) {
578 if constexpr (storm::IsIntervalType<ValueType>) {
579 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Result export for interval models is not supported.");
580 } else {
581 std::filesystem::path resultExportPath = ioSettings.getExportCheckResultFilename();
582 if (exportCount > 0) {
583 STORM_LOG_WARN("Prepending " << exportCount << " to result file name for this property because there are multiple properties.");
584 resultExportPath.replace_filename(std::to_string(exportCount) + resultExportPath.filename().string());
585 }
586 STORM_LOG_WARN_COND(sparseModel->hasStateValuations(),
587 "No information of state valuations available. The result output will use internal state ids. You might be interested in "
588 "building the model with state valuations using --buildstateval.");
589 storm::api::exportCheckResultToJson(sparseModel, result, resultExportPath);
590 }
591 }
592 ++exportCount;
593 };
594 if (!(ioSettings.isComputeSteadyStateDistributionSet() || ioSettings.isComputeExpectedVisitingTimesSet())) {
595 verifyProperties<ValueType>(input, verificationCallback, postprocessingCallback);
596 }
597 if (ioSettings.isComputeSteadyStateDistributionSet()) {
598 if constexpr (storm::IsIntervalType<ValueType>) {
599 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Computing steady state distribution is not supported for interval models.");
600 } else {
602 "steady-state probabilities",
603 [&mpi, &sparseModel]() { return storm::api::computeSteadyStateDistributionWithSparseEngine<ValueType>(mpi.env, sparseModel); }, input,
604 verificationCallback, postprocessingCallback);
605 }
606 }
607 if (ioSettings.isComputeExpectedVisitingTimesSet()) {
608 if constexpr (storm::IsIntervalType<ValueType>) {
609 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Computing expected visiting times is not supported for interval models.");
610 } else {
612 "expected visiting times",
613 [&mpi, &sparseModel]() { return storm::api::computeExpectedVisitingTimesWithSparseEngine<ValueType>(mpi.env, sparseModel); }, input,
614 verificationCallback, postprocessingCallback);
615 }
616 }
617}
618
619template<storm::dd::DdType DdType, typename ValueType>
620void verifyWithHybridEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& symbolicModel, SymbolicInput const& input,
621 ModelProcessingInformation const& mpi) {
623 input, [&symbolicModel, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
624 bool filterForInitialStates = states->isInitialFormula();
625 auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates);
626
627 std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithHybridEngine<DdType, ValueType>(mpi.env, symbolicModel, task);
628
629 std::unique_ptr<storm::modelchecker::CheckResult> filter;
630 if (filterForInitialStates) {
631 filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(),
632 symbolicModel->getInitialStates());
633 } else if (!states->isTrueFormula()) { // No need to apply filter if it is the formula 'true'
635 }
636 if (result && filter) {
637 result->filter(filter->asQualitativeCheckResult());
638 }
639 return result;
640 });
641}
642
643template<storm::dd::DdType DdType, typename ValueType>
644void verifyWithDdEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& symbolicModel, SymbolicInput const& input,
645 ModelProcessingInformation const& mpi) {
647 input, [&symbolicModel, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
648 bool filterForInitialStates = states->isInitialFormula();
649 auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates);
650
651 std::unique_ptr<storm::modelchecker::CheckResult> result =
653
654 std::unique_ptr<storm::modelchecker::CheckResult> filter;
655 if (filterForInitialStates) {
656 filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(),
657 symbolicModel->getInitialStates());
658 } else if (!states->isTrueFormula()) { // No need to apply filter if it is the formula 'true'
660 }
661 if (result && filter) {
662 result->filter(filter->asQualitativeCheckResult());
663 }
664 return result;
665 });
666}
667
668template<storm::dd::DdType DdType, typename ValueType>
670 ModelProcessingInformation const& mpi) {
672 verifyProperties<ValueType>(input, [&symbolicModel, &mpi, &options](std::shared_ptr<storm::logic::Formula const> const& formula,
673 std::shared_ptr<storm::logic::Formula const> const& states) {
674 STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Abstraction-refinement can only filter initial states.");
676 storm::api::createTask<ValueType>(formula, true), options);
677 });
678}
679
680template<storm::dd::DdType DdType, typename ValueType>
681typename std::enable_if<DdType != storm::dd::DdType::CUDD || std::is_same<ValueType, double>::value, void>::type verifyModel(
682 std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& symbolicModel, SymbolicInput const& input,
683 ModelProcessingInformation const& mpi) {
685 verifyWithHybridEngine<DdType, ValueType>(symbolicModel, input, mpi);
686 } else if (mpi.engine == storm::utility::Engine::Dd) {
687 verifyWithDdEngine<DdType, ValueType>(symbolicModel, input, mpi);
688 } else {
690 }
691}
692
693template<storm::dd::DdType DdType, typename ValueType>
694typename std::enable_if<DdType == storm::dd::DdType::CUDD && !std::is_same<ValueType, double>::value, void>::type verifySymbolicModel(
695 std::shared_ptr<storm::models::ModelBase> const&, SymbolicInput const&, ModelProcessingInformation const&) {
696 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "CUDD does not support the selected data-type.");
697}
698
699inline void processInput(SymbolicInput const& input, ModelProcessingInformation const& mpi) {
702
703 // For several engines, no model building step is performed, but the verification is started right away.
705 abstractionSettings.getAbstractionRefinementMethod() == storm::settings::modules::AbstractionSettings::Method::Games) {
707 [&input, &mpi]<storm::dd::DdType DD, typename VT>() { verifyWithAbstractionRefinementEngine<DD, VT>(input, mpi); });
709 applyValueType(mpi.verificationValueType, [&input, &mpi]<typename VT>() { verifyWithExplorationEngine<VT>(input, mpi); });
710 } else {
711 std::shared_ptr<storm::models::ModelBase> model = buildPreprocessExportModel(input, mpi);
712 if (model) {
713 if (counterexampleSettings.isCounterexampleSet()) {
714 castAndApply(model, [&input, &mpi](auto const& m) { generateCounterexamples(m, input, mpi); });
715 } else {
716 castAndApply(model, [&input, &mpi](auto const& m) { verifyModel(m, input, mpi); });
717 }
718 }
719 }
720}
721} // namespace cli
722} // namespace storm
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
std::shared_ptr< storm::logic::Formula const > getRawFormula() const
Definition Property.cpp:92
FilterExpression const & getFilter() const
Definition Property.cpp:88
static std::shared_ptr< Formula const > getTrueFormula()
Definition Formula.cpp:227
This class represents a discrete-time Markov chain.
Definition Dtmc.h:16
This class represents a (discrete-time) Markov decision process.
Definition Mdp.h:16
Base class for all sparse models.
Definition Model.h:34
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.
This class represents the settings for the abstraction procedures.
storm::jani::Model const & asJaniModel() const
static bool preservesFormula(storm::logic::Formula const &formula)
Check if the property specified by the given formula is preserved by the transformation.
A class that provides convenience operations to display run times.
Definition Stopwatch.h:13
void stop()
Stop stopwatch and add measured time to total time.
Definition Stopwatch.cpp:42
#define STORM_LOG_WARN(message)
Definition logging.h:35
#define STORM_LOG_TRACE(message)
Definition logging.h:22
#define STORM_LOG_ERROR(message)
Definition logging.h:36
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:54
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
std::unique_ptr< storm::modelchecker::CheckResult > verifyWithHybridEngine(storm::Environment const &env, std::shared_ptr< storm::models::symbolic::Dtmc< DdType, ValueType > > const &dtmc, storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &task)
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:80
storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > createTask(std::shared_ptr< const storm::logic::Formula > const &formula, bool onlyInitialStatesRelevant=false)
std::shared_ptr< storm::counterexamples::Counterexample > computeHighLevelCounterexampleMaxSmt(storm::Environment const &env, storm::storage::SymbolicModelDescription const &symbolicModel, std::shared_ptr< storm::models::sparse::Model< double > > model, std::shared_ptr< storm::logic::Formula const > const &formula, storm::counterexamples::SMTMinimalLabelSetGenerator< double >::Options const &options)
std::unique_ptr< storm::modelchecker::CheckResult > verifyWithExplorationEngine(storm::Environment const &env, storm::storage::SymbolicModelDescription const &model, storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &task)
void exportJaniModelAsDot(storm::jani::Model const &model, std::string const &filename)
Definition export.cpp:7
std::unique_ptr< storm::modelchecker::CheckResult > computeExpectedVisitingTimesWithSparseEngine(storm::Environment const &env, std::shared_ptr< storm::models::sparse::Dtmc< ValueType > > const &dtmc)
std::unique_ptr< storm::modelchecker::CheckResult > verifyWithDdEngine(storm::Environment const &env, std::shared_ptr< storm::models::symbolic::Dtmc< DdType, ValueType > > const &dtmc, storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &task)
std::shared_ptr< storm::logic::Formula const > checkAndTransformContinuousToDiscreteTimeFormula(storm::logic::Formula const &formula, std::string const &timeRewardName="_time")
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:127
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 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:94
std::unique_ptr< storm::modelchecker::CheckResult > verifyWithSparseEngine(storm::Environment const &env, std::shared_ptr< storm::models::sparse::Dtmc< ValueType > > const &dtmc, storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &task, bool preferEliminationChecker=false)
std::unique_ptr< storm::modelchecker::CheckResult > computeSteadyStateDistributionWithSparseEngine(storm::Environment const &env, std::shared_ptr< storm::models::sparse::Dtmc< ValueType > > const &dtmc)
std::shared_ptr< storm::counterexamples::Counterexample > computeHighLevelCounterexampleMilp(storm::Environment const &env, storm::storage::SymbolicModelDescription const &symbolicModel, std::shared_ptr< storm::models::sparse::Mdp< double > > mdp, std::shared_ptr< storm::logic::Formula const > const &formula, bool includeSchedulerCuts)
void exportSymbolicInput(SymbolicInput const &input)
void verifyWithAbstractionRefinementEngine(SymbolicInput const &input, ModelProcessingInformation const &mpi)
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)
void verifyWithExplorationEngine(SymbolicInput const &input, ModelProcessingInformation const &mpi)
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)
void generateCounterexamples(std::shared_ptr< ModelType > const &, SymbolicInput const &, ModelProcessingInformation const &)
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
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).
std::function< void(std::unique_ptr< storm::modelchecker::CheckResult > const &)> PostprocessingCallbackType
void printCounterexample(std::shared_ptr< storm::counterexamples::Counterexample > const &counterexample, storm::utility::Stopwatch *watch=nullptr)
void printModelCheckingProperty(storm::jani::Property const &property)
void verifyWithHybridEngine(std::shared_ptr< storm::models::symbolic::Model< DdType, ValueType > > const &symbolicModel, SymbolicInput const &input, ModelProcessingInformation const &mpi)
void printComputingCounterexample(storm::jani::Property const &property)
auto applyDdLibValueType(storm::dd::DdType dd, ModelProcessingInformation::ValueType vt, auto const &callback)
bool preferEliminationChecker()
Returns whether the settings request to prefer the dedicated elimination model checker.
void processInput(SymbolicInput const &input, ModelProcessingInformation const &mpi)
storm::gbar::api::AbstractionRefinementOptions getAbstractionRefinementOptions(storm::expressions::ExpressionManager const *expressionManager=nullptr)
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::enable_if<!std::is_same< ValueType, storm::RationalFunction >::value, std::unique_ptr< storm::modelchecker::CheckResult > >::type verifyWithAbstractionRefinementEngine(storm::Environment const &env, storm::storage::SymbolicModelDescription const &model, storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &task, AbstractionRefinementOptions const &options=AbstractionRefinementOptions())
storm::gbar::abstraction::AbstractionOptions AbstractionRefinementOptions
SettingsType const & getModule()
Get module.
OptimizationDirection convert(OptimizationDirectionSetting s)
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
bool isConstant(ValueType const &)
bool isInfinity(ValueType const &a)
TargetType convertNumber(SourceType const &number)
constexpr bool IsIntervalType
Helper to check if a type is an interval.
typename detail::IntervalMetaProgrammingHelper< ValueType >::BaseType IntervalBaseType
Helper to access the type in which interval boundaries are stored.
#define STORM_PRINT_AND_LOG(message)
Definition print.h:20
#define STORM_PRINT(message)
Define the macros that print information to stdout and optionally also log it.
Definition print.h:14
static const bool IsExact
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
bool useDecomposition
A flag indicating whether decomposition is to be used during the abstraction.
bool relativeTerminationCriterion
A flag indicating whether to use a relative termination criterion.
SolveMode solveMode
The mode with which to solve the abstractions.
bool restrictToValidBlocks
A flag indicating whether the abstractor restricts the initial states to valid blocks.
bool useInterpolation
A flag indicating whether interpolation is to be used to eliminate spurious pivot blocks.
ReuseMode reuseMode
The mode determining which results are reused.
bool fixPlayer1Strategy
A flag indicating whether player 1 strategies are to be fixed.
bool debug
A flag indicating whether debug mode is enabled.
std::vector< std::vector< storm::expressions::Expression > > injectedRefinementPredicates
Predicates that are injected (starting with the last one in this list) instead of the derived ones.
bool fixPlayer2Strategy
A flag indicating whether player 2 strategies are to be fixed.
bool addAllInitialExpressions
A flag indicating whether all initial expressions are added as initial predicates.
bool useEagerRefinement
A flag indicating whether to refine eagerly.
SplitMode splitMode
The mode that determines which predicates are split into atoms for the refinement.
bool rankRefinementPredicates
A flag indicating whether refinement predicates are to be ranked.
std::vector< storm::expressions::Expression > constraints
Additional constraints used by the abstraction.
bool addAllGuards
A flag indicating whether all guards are added as initial predicates.
bool restrictToRelevantStates
A flag indicating whether the abstractor restricts the abstraction to relevant states.
uint_fast64_t maximalNumberOfAbstractions
The maximal number of abstractions to perform until giving up on converging.
double precision
The precision used for detecting convergence.
PivotSelectionHeuristic pivotSelectionHeuristic
The heuristic to use for pivot block selection.