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 <sstream>
5
7
18
19namespace storm {
20namespace cli {
21
22inline void exportSymbolicInput(SymbolicInput const& input) {
24 if (input.model && input.model.get().isJaniModel()) {
25 storm::storage::SymbolicModelDescription const& model = input.model.get();
26 if (ioSettings.isExportJaniDotSet()) {
27 storm::api::exportJaniModelAsDot(model.asJaniModel(), ioSettings.getExportJaniDotFilename());
28 }
29 }
30}
31
33 STORM_PRINT("Computing counterexample for property " << *property.getRawFormula() << " ...\n");
34}
35
36inline void printCounterexample(std::shared_ptr<storm::counterexamples::Counterexample> const& counterexample, storm::utility::Stopwatch* watch = nullptr) {
37 if (counterexample) {
38 STORM_PRINT(*counterexample << '\n');
39 if (watch) {
40 STORM_PRINT("Time for computation: " << *watch << ".\n");
41 }
42 } else {
43 STORM_PRINT(" failed.\n");
44 }
45}
46
47template<typename ModelType>
48 requires(!std::derived_from<ModelType, storm::models::sparse::Model<double>>)
49inline void generateCounterexamples(std::shared_ptr<ModelType> const&, SymbolicInput const&) {
50 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Counterexample generation is not supported for this data-type.");
51}
52
53template<typename ModelType>
54 requires(std::derived_from<ModelType, storm::models::sparse::Model<double>>)
55inline void generateCounterexamples(std::shared_ptr<ModelType> const& sparseModel, SymbolicInput const& input) {
56 using ValueType = typename ModelType::ValueType;
57
58 for (auto& rewModel : sparseModel->getRewardModels()) {
59 rewModel.second.reduceToStateBasedRewards(sparseModel->getTransitionMatrix(), true);
60 }
61
62 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Dtmc) || sparseModel->isOfType(storm::models::ModelType::Mdp),
63 storm::exceptions::NotSupportedException, "Counterexample is currently only supported for discrete-time models.");
64
66 if (counterexampleSettings.isMinimalCommandSetGenerationSet()) {
67 bool useMilp = counterexampleSettings.isUseMilpBasedMinimalCommandSetGenerationSet();
68 for (auto const& property : input.properties) {
69 std::shared_ptr<storm::counterexamples::Counterexample> counterexample;
71 storm::utility::Stopwatch watch(true);
72 if (useMilp) {
73 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException,
74 "Counterexample generation using MILP is currently only supported for MDPs.");
76 input.model.get(), sparseModel->template as<storm::models::sparse::Mdp<ValueType>>(), property.getRawFormula());
77 } else {
78 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Dtmc) || sparseModel->isOfType(storm::models::ModelType::Mdp),
79 storm::exceptions::NotSupportedException,
80 "Counterexample generation using MaxSAT is currently only supported for discrete-time models.");
81
82 if (sparseModel->isOfType(storm::models::ModelType::Dtmc)) {
84 input.model.get(), sparseModel->template as<storm::models::sparse::Dtmc<ValueType>>(), property.getRawFormula());
85 } else {
87 input.model.get(), sparseModel->template as<storm::models::sparse::Mdp<ValueType>>(), property.getRawFormula());
88 }
89 }
90 watch.stop();
91 printCounterexample(counterexample, &watch);
92 }
93 } else if (counterexampleSettings.isShortestPathGenerationSet()) {
94 for (auto const& property : input.properties) {
95 std::shared_ptr<storm::counterexamples::Counterexample> counterexample;
97 storm::utility::Stopwatch watch(true);
98 STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Dtmc), storm::exceptions::NotSupportedException,
99 "Counterexample generation using shortest paths is currently only supported for DTMCs.");
101 property.getRawFormula(), counterexampleSettings.getShortestPathMaxK());
102 watch.stop();
103 printCounterexample(counterexample, &watch);
104 }
105 } else {
106 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The selected counterexample formalism is unsupported.");
107 }
108}
109
110template<typename ValueType>
112void printFilteredResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::modelchecker::FilterType ft) {
113 if (result->isQuantitative()) {
115 STORM_PRINT(*result);
116 } else {
117 ValueType resultValue;
118 switch (ft) {
120 resultValue = result->asQuantitativeCheckResult<ValueType>().sum();
121 break;
123 resultValue = result->asQuantitativeCheckResult<ValueType>().average();
124 break;
126 resultValue = result->asQuantitativeCheckResult<ValueType>().getMin();
127 break;
129 resultValue = result->asQuantitativeCheckResult<ValueType>().getMax();
130 break;
133 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Outputting states is not supported.");
137 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Filter type only defined for qualitative results.");
138 default:
139 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Unhandled filter type.");
140 }
142 STORM_PRINT(resultValue << " (approx. " << storm::utility::convertNumber<double>(resultValue) << ")");
143 } else {
144 STORM_PRINT(resultValue);
145 }
146 }
147 } else {
148 switch (ft) {
150 STORM_PRINT(*result << '\n');
151 break;
153 STORM_PRINT(result->asQualitativeCheckResult().existsTrue());
154 break;
156 STORM_PRINT(result->asQualitativeCheckResult().forallTrue());
157 break;
159 STORM_PRINT(result->asQualitativeCheckResult().count());
160 break;
163 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Outputting states is not supported.");
168 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Filter type only defined for quantitative results.");
169 }
170 }
171 STORM_PRINT('\n');
172}
173
174template<typename ValueType>
176void printResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::logic::Formula const& filterStatesFormula,
177 storm::modelchecker::FilterType const& filterType, storm::utility::Stopwatch* watch = nullptr) {
178 if (result) {
179 std::stringstream ss;
180 ss << "'" << filterStatesFormula << "'";
181 STORM_PRINT((storm::utility::resources::isTerminate() ? "Result till abort" : "Result")
182 << " (for " << (filterStatesFormula.isInitialFormula() ? "initial" : ss.str()) << " states): ");
183 printFilteredResult<ValueType>(result, filterType);
184 if (watch) {
185 STORM_PRINT("Time for model checking: " << *watch << ".\n");
186 }
187 } else {
188 STORM_LOG_ERROR("Property is unsupported by selected engine/settings.\n");
189 }
190}
191
192template<typename ValueType>
193void printResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::jani::Property const& property,
194 storm::utility::Stopwatch* watch = nullptr) {
195 printResult<ValueType>(result, *property.getFilter().getStatesFormula(), property.getFilter().getFilterType(), watch);
196}
197
198using VerificationCallbackType = std::function<std::unique_ptr<storm::modelchecker::CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula,
199 std::shared_ptr<storm::logic::Formula const> const& states)>;
200using PostprocessingCallbackType = std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)>;
201
203 void operator()(std::unique_ptr<storm::modelchecker::CheckResult> const&) {
204 // Intentionally left empty.
205 }
206};
207
214template<typename ValueType>
215std::unique_ptr<storm::modelchecker::CheckResult> verifyProperty(std::shared_ptr<storm::logic::Formula const> const& formula,
216 std::shared_ptr<storm::logic::Formula const> const& statesFilter,
217 VerificationCallbackType const& verificationCallback) {
219
220 try {
221 if constexpr (storm::IsIntervalType<ValueType>) {
222 STORM_LOG_ASSERT(!transformationSettings.isChainEliminationSet() && !transformationSettings.isToNondeterministicModelSet(),
223 "Unsupported transformation has been invoked.");
224 return verificationCallback(formula, statesFilter);
225 }
226 if (transformationSettings.isChainEliminationSet() && !storm::transformer::NonMarkovianChainTransformer<ValueType>::preservesFormula(*formula)) {
227 STORM_LOG_WARN("Property is not preserved by elimination of non-markovian states.");
228 } else if (transformationSettings.isToDiscreteTimeModelSet()) {
230 auto transformedStatesFilter = storm::api::checkAndTransformContinuousToDiscreteTimeFormula<ValueType>(*statesFilter);
231 if (transformedFormula && transformedStatesFilter) {
232 // invoke verification algorithm on transformed formulas
233 return verificationCallback(transformedFormula, transformedStatesFilter);
234 } else {
235 STORM_LOG_WARN("Property is not preserved by transformation to discrete time model.");
236 }
237 } else {
238 // invoke verification algorithm on given formulas
239 return verificationCallback(formula, statesFilter);
240 }
241 } catch (storm::exceptions::BaseException const& ex) {
242 STORM_LOG_WARN("Cannot handle property: " << ex.what());
243 }
244 return nullptr;
245}
246
253template<typename ValueType>
254void verifyProperties(SymbolicInput const& input, VerificationCallbackType const& verificationCallback,
255 PostprocessingCallbackType const& postprocessingCallback = PostprocessingIdentity()) {
256 auto const& properties = input.preprocessedProperties ? input.preprocessedProperties.get() : input.properties;
257 for (auto const& property : properties) {
259 storm::utility::Stopwatch watch(true);
260 auto result = verifyProperty<ValueType>(property.getRawFormula(), property.getFilter().getStatesFormula(), verificationCallback);
261 watch.stop();
262 if (result) {
263 postprocessingCallback(result);
264 }
265 printResult<storm::IntervalBaseType<ValueType>>(result, property, &watch);
266 }
267}
268
278template<typename ValueType>
279void computeStateValues(std::string const& description, std::function<std::unique_ptr<storm::modelchecker::CheckResult>()> const& computationCallback,
280 SymbolicInput const& input, VerificationCallbackType const& verificationCallback,
281 PostprocessingCallbackType const& postprocessingCallback = PostprocessingIdentity()) {
282 // First compute the state values for all the states by invoking the computationCallback
283 storm::utility::Stopwatch watch(true);
284 STORM_PRINT("\nComputing " << description << " ...\n");
285 std::unique_ptr<storm::modelchecker::CheckResult> result;
286 try {
287 result = computationCallback();
288 } catch (storm::exceptions::BaseException const& ex) {
289 STORM_LOG_ERROR("Cannot compute " << description << ": " << ex.what());
290 }
291 if (!result) {
292 STORM_LOG_ERROR("Computation had no result.");
293 return;
294 }
295 // Now process the (potentially filtered) result
296 if (input.properties.empty()) {
297 // Do not apply any filtering, consider result for *all* states
298 postprocessingCallback(result);
300 } else {
301 // Each property identifies a subset of states to which we restrict (aka filter) the state-value result to
302 auto const& properties = input.preprocessedProperties ? input.preprocessedProperties.get() : input.properties;
303 for (uint64_t propertyIndex = 0; propertyIndex < properties.size(); ++propertyIndex) {
304 auto const& property = properties[propertyIndex];
305 // As the property serves as filter, it should (a) be qualitative and should (b) not consider a filter itself.
306 if (!property.getRawFormula()->hasQualitativeResult()) {
307 STORM_LOG_ERROR("Property '" << *property.getRawFormula()
308 << "' can not be used for filtering states as it does not have a qualitative result.");
309 continue;
310 }
311
312 // Invoke verification algorithm on filtering property
313 auto propertyFilter = verifyProperty<ValueType>(property.getRawFormula(), storm::logic::Formula::getTrueFormula(), verificationCallback);
314
315 if (propertyFilter) {
316 // Filter and process result
317 std::unique_ptr<storm::modelchecker::CheckResult> filteredResult = result->clone();
318 filteredResult->filter(propertyFilter->asQualitativeCheckResult());
319 postprocessingCallback(filteredResult);
320 printResult<ValueType>(filteredResult, *property.getRawFormula(), property.getFilter().getFilterType(),
321 propertyIndex == properties.size() - 1 ? &watch : nullptr);
322 }
323 }
324 }
325}
326
327inline std::vector<storm::expressions::Expression> parseConstraints(storm::expressions::ExpressionManager const& expressionManager,
328 std::string const& constraintsString) {
329 std::vector<storm::expressions::Expression> constraints;
330
331 std::vector<std::string> constraintsAsStrings;
332 boost::split(constraintsAsStrings, constraintsString, boost::is_any_of(","));
333
334 storm::parser::ExpressionParser expressionParser(expressionManager);
335 std::unordered_map<std::string, storm::expressions::Expression> variableMapping;
336 for (auto const& variableTypePair : expressionManager) {
337 variableMapping[variableTypePair.first.getName()] = variableTypePair.first;
338 }
339 expressionParser.setIdentifierMapping(variableMapping);
340
341 for (auto const& constraintString : constraintsAsStrings) {
342 if (constraintString.empty()) {
343 continue;
344 }
345
346 storm::expressions::Expression constraint = expressionParser.parseFromString(constraintString);
347 STORM_LOG_TRACE("Adding special (user-provided) constraint " << constraint << ".");
348 constraints.emplace_back(constraint);
349 }
350
351 return constraints;
352}
353
354inline std::vector<std::vector<storm::expressions::Expression>> parseInjectedRefinementPredicates(
355 storm::expressions::ExpressionManager const& expressionManager, std::string const& refinementPredicatesString) {
356 std::vector<std::vector<storm::expressions::Expression>> injectedRefinementPredicates;
357
358 storm::parser::ExpressionParser expressionParser(expressionManager);
359 std::unordered_map<std::string, storm::expressions::Expression> variableMapping;
360 for (auto const& variableTypePair : expressionManager) {
361 variableMapping[variableTypePair.first.getName()] = variableTypePair.first;
362 }
363 expressionParser.setIdentifierMapping(variableMapping);
364
365 std::vector<std::string> predicateGroupsAsStrings;
366 boost::split(predicateGroupsAsStrings, refinementPredicatesString, boost::is_any_of(";"));
367
368 if (!predicateGroupsAsStrings.empty()) {
369 for (auto const& predicateGroupString : predicateGroupsAsStrings) {
370 if (predicateGroupString.empty()) {
371 continue;
372 }
373
374 std::vector<std::string> predicatesAsStrings;
375 boost::split(predicatesAsStrings, predicateGroupString, boost::is_any_of(":"));
376
377 if (!predicatesAsStrings.empty()) {
378 injectedRefinementPredicates.emplace_back();
379 for (auto const& predicateString : predicatesAsStrings) {
380 storm::expressions::Expression predicate = expressionParser.parseFromString(predicateString);
381 STORM_LOG_TRACE("Adding special (user-provided) refinement predicate " << predicateString << ".");
382 injectedRefinementPredicates.back().emplace_back(predicate);
383 }
384
385 STORM_LOG_THROW(!injectedRefinementPredicates.back().empty(), storm::exceptions::InvalidArgumentException,
386 "Expecting non-empty list of predicates to inject for each (mentioned) refinement step.");
387
388 // Finally reverse the list, because we take the predicates from the back.
389 std::reverse(injectedRefinementPredicates.back().begin(), injectedRefinementPredicates.back().end());
390 }
391 }
392
393 // Finally reverse the list, because we take the predicates from the back.
394 std::reverse(injectedRefinementPredicates.begin(), injectedRefinementPredicates.end());
395 }
396
397 return injectedRefinementPredicates;
398}
399
400template<storm::dd::DdType DdType, typename ValueType>
402 STORM_LOG_ASSERT(input.model, "Expected symbolic model description.");
405 parseConstraints(input.model->getManager(), abstractionSettings.getConstraintString()),
406 parseInjectedRefinementPredicates(input.model->getManager(), abstractionSettings.getInjectedRefinementPredicates()));
407
408 verifyProperties<ValueType>(input, [&input, &options, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula,
409 std::shared_ptr<storm::logic::Formula const> const& states) {
410 STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Abstraction-refinement can only filter initial states.");
412 storm::api::createTask<ValueType>(formula, true), options);
413 });
414}
415
416template<typename ValueType>
418 STORM_LOG_ASSERT(input.model, "Expected symbolic model description.");
419 STORM_LOG_THROW((std::is_same<ValueType, double>::value), storm::exceptions::NotSupportedException,
420 "Exploration does not support other data-types than floating points.");
422 input, [&input, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
423 STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Exploration can only filter initial states.");
425 });
426}
427
428template<typename ValueType>
429void verifyModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& sparseModel, SymbolicInput const& input,
430 ModelProcessingInformation const& mpi) {
432 auto verificationCallback = [&sparseModel, &ioSettings, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula,
433 std::shared_ptr<storm::logic::Formula const> const& states) {
434 auto createTask = [&ioSettings](auto const& f, bool onlyInitialStates) {
435 if constexpr (storm::IsIntervalType<ValueType>) {
436 STORM_LOG_THROW(ioSettings.isUncertaintyResolutionModeSet(), storm::exceptions::InvalidSettingsException,
437 "Uncertainty resolution mode required for uncertain (interval) models.");
438 return storm::api::createTask<ValueType>(f, storm::solver::convert(ioSettings.getUncertaintyResolutionMode()), onlyInitialStates);
439 } else {
440 (void)ioSettings; // suppress unused lambda capture warning. [[maybe_unused]] doesn't work for lambda captures.
441 return storm::api::createTask<ValueType>(f, onlyInitialStates);
442 }
443 };
444 bool const filterForInitialStates = states->isInitialFormula();
445 auto task = createTask(formula, filterForInitialStates);
446 if (ioSettings.isExportSchedulerSet()) {
447 task.setProduceSchedulers(true);
448 }
449 std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(mpi.env, sparseModel, task);
450
451 std::unique_ptr<storm::modelchecker::CheckResult> filter;
452 if (filterForInitialStates) {
453 using SolutionType = storm::IntervalBaseType<ValueType>;
454 filter = std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult<SolutionType>>(sparseModel->getInitialStates());
455 } else if (!states->isTrueFormula()) { // No need to apply filter if it is the formula 'true'
456 filter = storm::api::verifyWithSparseEngine<ValueType>(mpi.env, sparseModel, createTask(states, false));
457 }
458 if (result && filter) {
459 result->filter(filter->asQualitativeCheckResult());
460 }
461 return result;
462 };
463 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.
464 auto postprocessingCallback = [&sparseModel, &ioSettings, &input, &exportCount](std::unique_ptr<storm::modelchecker::CheckResult> const& result) {
465 // Scheduler export
466 STORM_LOG_WARN_COND(!ioSettings.isExportSchedulerSet() || result->hasScheduler(), "Scheduler requested but could not be generated.");
467 if (ioSettings.isExportSchedulerSet() && result->hasScheduler()) {
468 std::filesystem::path schedulerExportPath = ioSettings.getExportSchedulerFilename();
469 if (exportCount > 0) {
470 STORM_LOG_WARN("Prepending " << exportCount << " to scheduler file name for this property because there are multiple properties.");
471 schedulerExportPath.replace_filename(std::to_string(exportCount) + schedulerExportPath.filename().string());
472 }
473 STORM_PRINT_AND_LOG("Exporting scheduler ... ");
474 if (input.model) {
475 STORM_LOG_WARN_COND(sparseModel->hasStateValuations(),
476 "No information of state valuations available. The scheduler output will use internal state ids. You might be "
477 "interested in building the model with state valuations using --buildstateval.");
479 sparseModel->hasChoiceLabeling() || sparseModel->hasChoiceOrigins(),
480 "No symbolic choice information is available. The scheduler output will use internal choice ids. You might be interested in "
481 "building the model with choice labels or choice origins using --buildchoicelab or --buildchoiceorig.");
482 STORM_LOG_WARN_COND(sparseModel->hasChoiceLabeling() && !sparseModel->hasChoiceOrigins(),
483 "Only partial choice information is available. You might want to build the model with choice origins using "
484 "--buildchoicelab or --buildchoiceorig.");
485 }
486 if (result->isExplicitQuantitativeCheckResult()) {
487 if constexpr (storm::IsIntervalType<ValueType>) {
488 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export for interval models is not supported.");
489 } else {
490 storm::api::exportScheduler(sparseModel, result->template asExplicitQuantitativeCheckResult<ValueType>().getScheduler(),
491 schedulerExportPath.string());
492 }
493 } else if (result->isExplicitParetoCurveCheckResult()) {
494 if constexpr (std::is_same_v<ValueType, storm::RationalFunction> || storm::IsIntervalType<ValueType>) {
495 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export for models of this value type is not supported.");
496 } else {
497 auto const& paretoRes = result->template asExplicitParetoCurveCheckResult<ValueType>();
498 storm::api::exportParetoScheduler(sparseModel, paretoRes.getPoints(), paretoRes.getSchedulers(), schedulerExportPath.string());
499 }
500 } else if (result->isExplicitQualitativeCheckResult()) {
501 if constexpr (storm::IsIntervalType<ValueType>) {
502 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export for interval models is not supported.");
503 } else {
504 storm::api::exportScheduler(sparseModel, result->template asExplicitQualitativeCheckResult<ValueType>().getScheduler(),
505 schedulerExportPath.string());
506 }
507 } else {
508 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export not supported for this value type.");
509 }
510 }
511
512 // Result export
513 if (ioSettings.isExportCheckResultSet()) {
514 if constexpr (storm::IsIntervalType<ValueType>) {
515 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Result export for interval models is not supported.");
516 } else {
517 std::filesystem::path resultExportPath = ioSettings.getExportCheckResultFilename();
518 if (exportCount > 0) {
519 STORM_LOG_WARN("Prepending " << exportCount << " to result file name for this property because there are multiple properties.");
520 resultExportPath.replace_filename(std::to_string(exportCount) + resultExportPath.filename().string());
521 }
522 STORM_LOG_WARN_COND(sparseModel->hasStateValuations(),
523 "No information of state valuations available. The result output will use internal state ids. You might be interested in "
524 "building the model with state valuations using --buildstateval.");
525 storm::api::exportCheckResultToJson(sparseModel, result, resultExportPath);
526 }
527 }
528 ++exportCount;
529 };
530 if (!(ioSettings.isComputeSteadyStateDistributionSet() || ioSettings.isComputeExpectedVisitingTimesSet())) {
531 verifyProperties<ValueType>(input, verificationCallback, postprocessingCallback);
532 }
533 if (ioSettings.isComputeSteadyStateDistributionSet()) {
534 if constexpr (storm::IsIntervalType<ValueType>) {
535 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Computing steady state distribution is not supported for interval models.");
536 } else {
538 "steady-state probabilities",
539 [&mpi, &sparseModel]() { return storm::api::computeSteadyStateDistributionWithSparseEngine<ValueType>(mpi.env, sparseModel); }, input,
540 verificationCallback, postprocessingCallback);
541 }
542 }
543 if (ioSettings.isComputeExpectedVisitingTimesSet()) {
544 if constexpr (storm::IsIntervalType<ValueType>) {
545 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Computing expected visiting times is not supported for interval models.");
546 } else {
548 "expected visiting times",
549 [&mpi, &sparseModel]() { return storm::api::computeExpectedVisitingTimesWithSparseEngine<ValueType>(mpi.env, sparseModel); }, input,
550 verificationCallback, postprocessingCallback);
551 }
552 }
553}
554
555template<storm::dd::DdType DdType, typename ValueType>
556void verifyWithHybridEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& symbolicModel, SymbolicInput const& input,
557 ModelProcessingInformation const& mpi) {
559 input, [&symbolicModel, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
560 bool filterForInitialStates = states->isInitialFormula();
561 auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates);
562
563 std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithHybridEngine<DdType, ValueType>(mpi.env, symbolicModel, task);
564
565 std::unique_ptr<storm::modelchecker::CheckResult> filter;
566 if (filterForInitialStates) {
567 filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(),
568 symbolicModel->getInitialStates());
569 } else if (!states->isTrueFormula()) { // No need to apply filter if it is the formula 'true'
571 }
572 if (result && filter) {
573 result->filter(filter->asQualitativeCheckResult());
574 }
575 return result;
576 });
577}
578
579template<storm::dd::DdType DdType, typename ValueType>
580void verifyWithDdEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& symbolicModel, SymbolicInput const& input,
581 ModelProcessingInformation const& mpi) {
583 input, [&symbolicModel, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
584 bool filterForInitialStates = states->isInitialFormula();
585 auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates);
586
587 std::unique_ptr<storm::modelchecker::CheckResult> result =
589
590 std::unique_ptr<storm::modelchecker::CheckResult> filter;
591 if (filterForInitialStates) {
592 filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(),
593 symbolicModel->getInitialStates());
594 } else if (!states->isTrueFormula()) { // No need to apply filter if it is the formula 'true'
596 }
597 if (result && filter) {
598 result->filter(filter->asQualitativeCheckResult());
599 }
600 return result;
601 });
602}
603
604template<storm::dd::DdType DdType, typename ValueType>
606 ModelProcessingInformation const& mpi) {
608 input, [&symbolicModel, &mpi](std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
609 STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Abstraction-refinement can only filter initial states.");
611 storm::api::createTask<ValueType>(formula, true));
612 });
613}
614
615template<storm::dd::DdType DdType, typename ValueType>
616typename std::enable_if<DdType != storm::dd::DdType::CUDD || std::is_same<ValueType, double>::value, void>::type verifyModel(
617 std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& symbolicModel, SymbolicInput const& input,
618 ModelProcessingInformation const& mpi) {
620 verifyWithHybridEngine<DdType, ValueType>(symbolicModel, input, mpi);
621 } else if (mpi.engine == storm::utility::Engine::Dd) {
622 verifyWithDdEngine<DdType, ValueType>(symbolicModel, input, mpi);
623 } else {
625 }
626}
627
628template<storm::dd::DdType DdType, typename ValueType>
629typename std::enable_if<DdType == storm::dd::DdType::CUDD && !std::is_same<ValueType, double>::value, void>::type verifySymbolicModel(
630 std::shared_ptr<storm::models::ModelBase> const&, SymbolicInput const&, ModelProcessingInformation const&) {
631 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "CUDD does not support the selected data-type.");
632}
633
634inline void processInput(SymbolicInput const& input, ModelProcessingInformation const& mpi) {
637
638 // For several engines, no model building step is performed, but the verification is started right away.
640 abstractionSettings.getAbstractionRefinementMethod() == storm::settings::modules::AbstractionSettings::Method::Games) {
642 [&input, &mpi]<storm::dd::DdType DD, typename VT>() { verifyWithAbstractionRefinementEngine<DD, VT>(input, mpi); });
644 applyValueType(mpi.verificationValueType, [&input, &mpi]<typename VT>() { verifyWithExplorationEngine<VT>(input, mpi); });
645 } else {
646 std::shared_ptr<storm::models::ModelBase> model = buildPreprocessExportModel(input, mpi);
647 if (model) {
648 if (counterexampleSettings.isCounterexampleSet()) {
649 castAndApply(model, [&input](auto const& m) { generateCounterexamples(m, input); });
650 } else {
651 castAndApply(model, [&input, &mpi](auto const& m) { verifyModel(m, input, mpi); });
652 }
653 }
654 }
655}
656} // namespace cli
657} // 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:213
This class represents a discrete-time Markov chain.
Definition Dtmc.h:13
This class represents a (discrete-time) Markov decision process.
Definition Mdp.h:13
Base class for all sparse models.
Definition Model.h:30
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.
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.
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:28
#define STORM_LOG_TRACE(message)
Definition logging.h:15
#define STORM_LOG_ERROR(message)
Definition logging.h:29
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:36
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
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 > 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::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")
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)
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)
std::unique_ptr< storm::modelchecker::CheckResult > computeSteadyStateDistributionWithSparseEngine(storm::Environment const &env, std::shared_ptr< storm::models::sparse::Dtmc< ValueType > > const &dtmc)
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 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)
void processInput(SymbolicInput const &input, ModelProcessingInformation const &mpi)
void generateCounterexamples(std::shared_ptr< ModelType > const &, SymbolicInput const &)
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())
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 &)
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