You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

920 lines
58 KiB

8 years ago
6 years ago
8 years ago
6 years ago
6 years ago
8 years ago
8 years ago
6 years ago
8 years ago
6 years ago
8 years ago
6 years ago
6 years ago
8 years ago
6 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
8 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. #include "storm-cli-utilities/cli.h"
  2. #include "storm-cli-utilities/model-handling.h"
  3. #include "storm-pars/api/storm-pars.h"
  4. #include "storm-pars/api/region.h"
  5. #include "storm-pars/analysis/MonotonicityHelper.h"
  6. #include "storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h"
  7. #include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h"
  8. #include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h"
  9. #include "storm-pars/settings/ParsSettings.h"
  10. #include "storm-pars/settings/modules/ParametricSettings.h"
  11. #include "storm-pars/settings/modules/MonotonicitySettings.h"
  12. #include "storm-pars/settings/modules/RegionSettings.h"
  13. #include "storm-pars/transformer/SparseParametricMdpSimplifier.h"
  14. #include "storm-pars/transformer/SparseParametricDtmcSimplifier.h"
  15. #include "storm/api/storm.h"
  16. #include "storm/exceptions/BaseException.h"
  17. #include "storm/exceptions/InvalidSettingsException.h"
  18. #include "storm/exceptions/NotSupportedException.h"
  19. #include "storm/models/ModelBase.h"
  20. #include "storm/settings/SettingsManager.h"
  21. #include "storm/solver/stateelimination/NondeterministicModelStateEliminator.h"
  22. #include "storm/storage/StronglyConnectedComponentDecomposition.h"
  23. #include "storm/storage/SymbolicModelDescription.h"
  24. #include "storm/io/file.h"
  25. #include "storm/utility/initialize.h"
  26. #include "storm/utility/Stopwatch.h"
  27. #include "storm/utility/macros.h"
  28. #include "storm/utility/Engine.h"
  29. #include "storm/settings/modules/GeneralSettings.h"
  30. #include "storm/settings/modules/CoreSettings.h"
  31. #include "storm/settings/modules/IOSettings.h"
  32. #include "storm/settings/modules/BisimulationSettings.h"
  33. #include "storm/settings/modules/TransformationSettings.h"
  34. namespace storm {
  35. namespace pars {
  36. typedef typename storm::cli::SymbolicInput SymbolicInput;
  37. template <typename ValueType>
  38. struct SampleInformation {
  39. SampleInformation(bool graphPreserving = false, bool exact = false) : graphPreserving(graphPreserving), exact(exact) {
  40. // Intentionally left empty.
  41. }
  42. bool empty() const {
  43. return cartesianProducts.empty();
  44. }
  45. std::vector<std::map<typename utility::parametric::VariableType<ValueType>::type, std::vector<typename utility::parametric::CoefficientType<ValueType>::type>>> cartesianProducts;
  46. bool graphPreserving;
  47. bool exact;
  48. };
  49. struct PreprocessResult {
  50. PreprocessResult(std::shared_ptr<storm::models::ModelBase> const& model, bool changed) : changed(changed), model(model) {
  51. // Intentionally left empty.
  52. }
  53. bool changed;
  54. std::shared_ptr<storm::models::ModelBase> model;
  55. boost::optional<std::vector<std::shared_ptr<storm::logic::Formula const>>> formulas;
  56. };
  57. template <typename ValueType>
  58. std::vector<storm::storage::ParameterRegion<ValueType>> parseRegions(std::shared_ptr<storm::models::ModelBase> const& model) {
  59. std::vector<storm::storage::ParameterRegion<ValueType>> result;
  60. auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>();
  61. boost::optional<int> splittingThreshold;
  62. if (regionSettings.isSplittingThresholdSet()) {
  63. splittingThreshold = regionSettings.getSplittingThreshold();
  64. }
  65. if (regionSettings.isRegionSet()) {
  66. result = storm::api::parseRegions<ValueType>(regionSettings.getRegionString(), *model, splittingThreshold);
  67. } else if (regionSettings.isRegionBoundSet()) {
  68. result = storm::api::createRegion<ValueType>(regionSettings.getRegionBoundString(), *model, splittingThreshold);
  69. }
  70. return result;
  71. }
  72. template <typename ValueType>
  73. SampleInformation<ValueType> parseSamples(std::shared_ptr<storm::models::ModelBase> const& model, std::string const& sampleString, bool graphPreserving) {
  74. STORM_LOG_THROW(!model || model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models.");
  75. SampleInformation<ValueType> sampleInfo(graphPreserving);
  76. if (sampleString.empty()) {
  77. return sampleInfo;
  78. }
  79. // Get all parameters from the model.
  80. std::set<typename utility::parametric::VariableType<ValueType>::type> modelParameters;
  81. auto const& sparseModel = *model->as<storm::models::sparse::Model<ValueType>>();
  82. modelParameters = storm::models::sparse::getProbabilityParameters(sparseModel);
  83. auto rewParameters = storm::models::sparse::getRewardParameters(sparseModel);
  84. modelParameters.insert(rewParameters.begin(), rewParameters.end());
  85. std::vector<std::string> cartesianProducts;
  86. boost::split(cartesianProducts, sampleString, boost::is_any_of(";"));
  87. for (auto& product : cartesianProducts) {
  88. boost::trim(product);
  89. // Get the values string for each variable.
  90. std::vector<std::string> valuesForVariables;
  91. boost::split(valuesForVariables, product, boost::is_any_of(","));
  92. for (auto& values : valuesForVariables) {
  93. boost::trim(values);
  94. }
  95. std::set<typename utility::parametric::VariableType<ValueType>::type> encounteredParameters;
  96. sampleInfo.cartesianProducts.emplace_back();
  97. auto& newCartesianProduct = sampleInfo.cartesianProducts.back();
  98. for (auto const& varValues : valuesForVariables) {
  99. auto equalsPosition = varValues.find("=");
  100. STORM_LOG_THROW(equalsPosition != varValues.npos, storm::exceptions::WrongFormatException, "Incorrect format of samples.");
  101. std::string variableName = varValues.substr(0, equalsPosition);
  102. boost::trim(variableName);
  103. std::string values = varValues.substr(equalsPosition + 1);
  104. boost::trim(values);
  105. bool foundParameter = false;
  106. typename utility::parametric::VariableType<ValueType>::type theParameter;
  107. for (auto const& parameter : modelParameters) {
  108. std::stringstream parameterStream;
  109. parameterStream << parameter;
  110. if (parameterStream.str() == variableName) {
  111. foundParameter = true;
  112. theParameter = parameter;
  113. encounteredParameters.insert(parameter);
  114. }
  115. }
  116. STORM_LOG_THROW(foundParameter, storm::exceptions::WrongFormatException, "Unknown parameter '" << variableName << "'.");
  117. std::vector<std::string> splitValues;
  118. boost::split(splitValues, values, boost::is_any_of(":"));
  119. STORM_LOG_THROW(!splitValues.empty(), storm::exceptions::WrongFormatException, "Expecting at least one value per parameter.");
  120. auto& list = newCartesianProduct[theParameter];
  121. for (auto& value : splitValues) {
  122. boost::trim(value);
  123. list.push_back(storm::utility::convertNumber<typename utility::parametric::CoefficientType<ValueType>::type>(value));
  124. }
  125. }
  126. STORM_LOG_THROW(encounteredParameters == modelParameters, storm::exceptions::WrongFormatException, "Variables for all parameters are required when providing samples.");
  127. }
  128. return sampleInfo;
  129. }
  130. template <typename ValueType>
  131. std::shared_ptr<storm::models::ModelBase> eliminateScc(std::shared_ptr<storm::models::ModelBase> const& model) {
  132. storm::utility::Stopwatch eliminationWatch(true);
  133. std::shared_ptr<storm::models::ModelBase> result;
  134. if (model->isOfType(storm::models::ModelType::Dtmc)) {
  135. STORM_PRINT("Applying scc elimination" << std::endl);
  136. auto sparseModel = model->as<storm::models::sparse::Model<ValueType>>();
  137. auto matrix = sparseModel->getTransitionMatrix();
  138. auto backwardsTransitionMatrix = matrix.transpose();
  139. storm::storage::StronglyConnectedComponentDecompositionOptions const options;
  140. auto decomposition = storm::storage::StronglyConnectedComponentDecomposition<ValueType>(matrix, options);
  141. storm::storage::BitVector selectedStates(matrix.getRowCount());
  142. storm::storage::BitVector selfLoopStates(matrix.getRowCount());
  143. for (size_t i = 0; i < decomposition.size(); ++i) {
  144. auto scc = decomposition.getBlock(i);
  145. if (scc.size() > 1) {
  146. auto statesScc = scc.getStates();
  147. std::vector<uint_fast64_t> entryStates;
  148. for (auto state : statesScc) {
  149. auto row = backwardsTransitionMatrix.getRow(state);
  150. bool found = false;
  151. for (auto backState : row) {
  152. if (!scc.containsState(backState.getColumn())) {
  153. found = true;
  154. }
  155. }
  156. if (found) {
  157. entryStates.push_back(state);
  158. selfLoopStates.set(state);
  159. } else {
  160. selectedStates.set(state);
  161. }
  162. }
  163. if (entryStates.size() != 1) {
  164. STORM_LOG_THROW(entryStates.size() > 1, storm::exceptions::NotImplementedException,
  165. "state elimination not implemented for scc with more than 1 entry points");
  166. }
  167. }
  168. }
  169. storm::storage::FlexibleSparseMatrix<ValueType> flexibleMatrix(matrix);
  170. storm::storage::FlexibleSparseMatrix<ValueType> flexibleBackwardTransitions(backwardsTransitionMatrix, true);
  171. auto actionRewards = std::vector<ValueType>(matrix.getRowCount(), storm::utility::zero<ValueType>());
  172. storm::solver::stateelimination::NondeterministicModelStateEliminator<ValueType> stateEliminator(flexibleMatrix, flexibleBackwardTransitions, actionRewards);
  173. for(auto state : selectedStates) {
  174. stateEliminator.eliminateState(state, true);
  175. }
  176. for (auto state : selfLoopStates) {
  177. auto row = flexibleMatrix.getRow(state);
  178. stateEliminator.eliminateLoop(state);
  179. }
  180. selectedStates.complement();
  181. auto keptRows = matrix.getRowFilter(selectedStates);
  182. storm::storage::SparseMatrix<ValueType> newTransitionMatrix = flexibleMatrix.createSparseMatrix(keptRows, selectedStates);
  183. // TODO @Jip: note that rewards get lost
  184. result = std::make_shared<storm::models::sparse::Dtmc<ValueType>>(std::move(newTransitionMatrix), sparseModel->getStateLabeling().getSubLabeling(selectedStates));
  185. eliminationWatch.stop();
  186. STORM_PRINT(std::endl << "Time for scc elimination: " << eliminationWatch << "." << std::endl << std::endl);
  187. result->printModelInformationToStream(std::cout);
  188. } else if (model->isOfType(storm::models::ModelType::Mdp)) {
  189. STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Unable to perform SCC elimination for monotonicity analysis on MDP: Not mplemented");
  190. } else {
  191. STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type.");
  192. }
  193. return result;
  194. }
  195. template <typename ValueType>
  196. std::shared_ptr<storm::models::ModelBase> simplifyModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) {
  197. storm::utility::Stopwatch simplifyingWatch(true);
  198. std::shared_ptr<storm::models::ModelBase> result;
  199. if (model->isOfType(storm::models::ModelType::Dtmc)) {
  200. storm::transformer::SparseParametricDtmcSimplifier<storm::models::sparse::Dtmc<ValueType>> simplifier(*(model->template as<storm::models::sparse::Dtmc<ValueType>>()));
  201. std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::api::extractFormulasFromProperties(input.properties);
  202. STORM_LOG_THROW(formulas.begin()!=formulas.end(), storm::exceptions::NotSupportedException, "Only one formula at the time supported");
  203. if (!simplifier.simplify(*(formulas[0]))) {
  204. STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull.");
  205. }
  206. result = simplifier.getSimplifiedModel();
  207. } else if (model->isOfType(storm::models::ModelType::Mdp)) {
  208. storm::transformer::SparseParametricMdpSimplifier<storm::models::sparse::Mdp<ValueType>> simplifier(*(model->template as<storm::models::sparse::Mdp<ValueType>>()));
  209. std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::api::extractFormulasFromProperties(input.properties);
  210. STORM_LOG_THROW(formulas.begin()!=formulas.end(), storm::exceptions::NotSupportedException, "Only one formula at the time supported");
  211. if (!simplifier.simplify(*(formulas[0]))) {
  212. STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull.");
  213. }
  214. result = simplifier.getSimplifiedModel();
  215. } else {
  216. STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type.");
  217. }
  218. simplifyingWatch.stop();
  219. STORM_PRINT(std::endl << "Time for model simplification: " << simplifyingWatch << "." << std::endl << std::endl);
  220. result->printModelInformationToStream(std::cout);
  221. return result;
  222. }
  223. template <typename ValueType>
  224. PreprocessResult preprocessSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, storm::cli::ModelProcessingInformation const& mpi) {
  225. auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>();
  226. auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>();
  227. auto transformationSettings = storm::settings::getModule<storm::settings::modules::TransformationSettings>();
  228. auto monSettings = storm::settings::getModule<storm::settings::modules::MonotonicitySettings>();
  229. PreprocessResult result(model, false);
  230. if (monSettings.isMonotonicityAnalysisSet() || parametricSettings.isUseMonotonicitySet()) {
  231. result.model = storm::pars::simplifyModel<ValueType>(result.model, input);
  232. result.changed = true;
  233. }
  234. if (result.model->isOfType(storm::models::ModelType::MarkovAutomaton)) {
  235. result.model = storm::cli::preprocessSparseMarkovAutomaton(result.model->template as<storm::models::sparse::MarkovAutomaton<ValueType>>());
  236. result.changed = true;
  237. }
  238. if (mpi.applyBisimulation) {
  239. result.model = storm::cli::preprocessSparseModelBisimulation(result.model->template as<storm::models::sparse::Model<ValueType>>(), input, bisimulationSettings);
  240. result.changed = true;
  241. }
  242. if (transformationSettings.isChainEliminationSet() &&
  243. model->isOfType(storm::models::ModelType::MarkovAutomaton)) {
  244. auto eliminationResult = storm::api::eliminateNonMarkovianChains(
  245. result.model->template as<storm::models::sparse::MarkovAutomaton<ValueType>>(),
  246. storm::api::extractFormulasFromProperties(input.properties),
  247. transformationSettings.getLabelBehavior());
  248. result.model = eliminationResult.first;
  249. // Set transformed properties as new properties in input
  250. result.formulas = eliminationResult.second;
  251. result.changed = true;
  252. }
  253. if (parametricSettings.transformContinuousModel() && (model->isOfType(storm::models::ModelType::Ctmc) || model->isOfType(storm::models::ModelType::MarkovAutomaton))) {
  254. auto transformResult = storm::api::transformContinuousToDiscreteTimeSparseModel(std::move(*model->template as<storm::models::sparse::Model<ValueType>>()), storm::api::extractFormulasFromProperties(input.properties));
  255. result.model = transformResult.first;
  256. // Set transformed properties as new properties in input
  257. result.formulas = transformResult.second;
  258. result.changed = true;
  259. }
  260. if (monSettings.isSccEliminationSet()) {
  261. result.model = storm::pars::eliminateScc<ValueType>(result.model);
  262. result.changed = true;
  263. }
  264. return result;
  265. }
  266. template <storm::dd::DdType DdType, typename ValueType>
  267. PreprocessResult preprocessDdModel(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input, storm::cli::ModelProcessingInformation const& mpi) {
  268. auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>();
  269. PreprocessResult result(model, false);
  270. if (mpi.engine == storm::utility::Engine::Hybrid) {
  271. // Currently, hybrid engine for parametric models just refers to building the model symbolically.
  272. STORM_LOG_INFO("Translating symbolic model to sparse model...");
  273. result.model = storm::api::transformSymbolicToSparseModel(model);
  274. result.changed = true;
  275. // Invoke preprocessing on the sparse model
  276. PreprocessResult sparsePreprocessingResult = storm::pars::preprocessSparseModel<ValueType>(result.model->as<storm::models::sparse::Model<ValueType>>(), input, mpi);
  277. if (sparsePreprocessingResult.changed) {
  278. result.model = sparsePreprocessingResult.model;
  279. result.formulas = sparsePreprocessingResult.formulas;
  280. }
  281. } else {
  282. STORM_LOG_ASSERT(mpi.engine == storm::utility::Engine::Dd, "Expected Dd engine.");
  283. if (mpi.applyBisimulation) {
  284. result.model = storm::cli::preprocessDdModelBisimulation(result.model->template as<storm::models::symbolic::Model<DdType, ValueType>>(), input, bisimulationSettings, mpi);
  285. result.changed = true;
  286. }
  287. }
  288. return result;
  289. }
  290. template <storm::dd::DdType DdType, typename ValueType>
  291. PreprocessResult preprocessModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, storm::cli::ModelProcessingInformation const& mpi) {
  292. storm::utility::Stopwatch preprocessingWatch(true);
  293. PreprocessResult result(model, false);
  294. if (model->isSparseModel()) {
  295. result = storm::pars::preprocessSparseModel<ValueType>(result.model->as<storm::models::sparse::Model<ValueType>>(), input, mpi);
  296. } else {
  297. STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type.");
  298. result = storm::pars::preprocessDdModel<DdType, ValueType>(result.model->as<storm::models::symbolic::Model<DdType, ValueType>>(), input, mpi);
  299. }
  300. if (result.changed) {
  301. STORM_PRINT_AND_LOG(std::endl << "Time for model preprocessing: " << preprocessingWatch << "." << std::endl << std::endl);
  302. }
  303. return result;
  304. }
  305. template<typename ValueType>
  306. void printInitialStatesResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr, storm::utility::parametric::Valuation<ValueType> const* valuation = nullptr) {
  307. if (result) {
  308. STORM_PRINT_AND_LOG("Result (initial states)");
  309. if (valuation) {
  310. bool first = true;
  311. std::stringstream ss;
  312. for (auto const& entry : *valuation) {
  313. if (!first) {
  314. ss << ", ";
  315. } else {
  316. first = false;
  317. }
  318. ss << entry.first << "=" << entry.second;
  319. }
  320. STORM_PRINT_AND_LOG(" for instance [" << ss.str() << "]");
  321. }
  322. STORM_PRINT_AND_LOG(": ")
  323. auto const* regionCheckResult = dynamic_cast<storm::modelchecker::RegionCheckResult<ValueType> const*>(result.get());
  324. if (regionCheckResult != nullptr) {
  325. auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>();
  326. std::stringstream outStream;
  327. if (regionSettings.isPrintFullResultSet()) {
  328. regionCheckResult->writeToStream(outStream);
  329. } else {
  330. regionCheckResult->writeCondensedToStream(outStream);
  331. }
  332. outStream << std::endl;
  333. if (!regionSettings.isPrintNoIllustrationSet()) {
  334. auto const* regionRefinementCheckResult = dynamic_cast<storm::modelchecker::RegionRefinementCheckResult<ValueType> const*>(regionCheckResult);
  335. if (regionRefinementCheckResult != nullptr) {
  336. regionRefinementCheckResult->writeIllustrationToStream(outStream);
  337. }
  338. }
  339. outStream << std::endl;
  340. STORM_PRINT_AND_LOG(outStream.str());
  341. } else {
  342. STORM_PRINT_AND_LOG(*result << std::endl);
  343. }
  344. if (watch) {
  345. STORM_PRINT_AND_LOG("Time for model checking: " << *watch << "." << std::endl << std::endl);
  346. }
  347. } else {
  348. STORM_LOG_ERROR("Property is unsupported by selected engine/settings." << std::endl);
  349. }
  350. }
  351. template<typename ValueType>
  352. void verifyProperties(std::vector<storm::jani::Property> const& properties, std::function<std::unique_ptr<storm::modelchecker::CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula)> const& verificationCallback, std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)> const& postprocessingCallback) {
  353. for (auto const& property : properties) {
  354. storm::cli::printModelCheckingProperty(property);
  355. storm::utility::Stopwatch watch(true);
  356. std::unique_ptr<storm::modelchecker::CheckResult> result = verificationCallback(property.getRawFormula());
  357. watch.stop();
  358. printInitialStatesResult<ValueType>(result, property, &watch);
  359. postprocessingCallback(result);
  360. }
  361. }
  362. template<template<typename, typename> class ModelCheckerType, typename ModelType, typename ValueType, typename SolveValueType = double>
  363. void verifyPropertiesAtSamplePoints(ModelType const& model, SymbolicInput const& input, SampleInformation<ValueType> const& samples) {
  364. // When samples are provided, we create an instantiation model checker.
  365. ModelCheckerType<ModelType, SolveValueType> modelchecker(model);
  366. for (auto const& property : input.properties) {
  367. storm::cli::printModelCheckingProperty(property);
  368. modelchecker.specifyFormula(storm::api::createTask<ValueType>(property.getRawFormula(), true));
  369. modelchecker.setInstantiationsAreGraphPreserving(samples.graphPreserving);
  370. storm::utility::parametric::Valuation<ValueType> valuation;
  371. std::vector<typename utility::parametric::VariableType<ValueType>::type> parameters;
  372. std::vector<typename std::vector<typename utility::parametric::CoefficientType<ValueType>::type>::const_iterator> iterators;
  373. std::vector<typename std::vector<typename utility::parametric::CoefficientType<ValueType>::type>::const_iterator> iteratorEnds;
  374. storm::utility::Stopwatch watch(true);
  375. for (auto const& product : samples.cartesianProducts) {
  376. parameters.clear();
  377. iterators.clear();
  378. iteratorEnds.clear();
  379. for (auto const& entry : product) {
  380. parameters.push_back(entry.first);
  381. iterators.push_back(entry.second.cbegin());
  382. iteratorEnds.push_back(entry.second.cend());
  383. }
  384. bool done = false;
  385. while (!done) {
  386. // Read off valuation.
  387. for (uint64_t i = 0; i < parameters.size(); ++i) {
  388. valuation[parameters[i]] = *iterators[i];
  389. }
  390. storm::utility::Stopwatch valuationWatch(true);
  391. std::unique_ptr<storm::modelchecker::CheckResult> result = modelchecker.check(Environment(), valuation);
  392. valuationWatch.stop();
  393. if (result) {
  394. result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model.getInitialStates()));
  395. }
  396. printInitialStatesResult<ValueType>(result, property, &valuationWatch, &valuation);
  397. for (uint64_t i = 0; i < parameters.size(); ++i) {
  398. ++iterators[i];
  399. if (iterators[i] == iteratorEnds[i]) {
  400. // Reset iterator and proceed to move next iterator.
  401. iterators[i] = product.at(parameters[i]).cbegin();
  402. // If the last iterator was removed, we are done.
  403. if (i == parameters.size() - 1) {
  404. done = true;
  405. }
  406. } else {
  407. // If an iterator was moved but not reset, we have another valuation to check.
  408. break;
  409. }
  410. }
  411. }
  412. }
  413. watch.stop();
  414. STORM_PRINT_AND_LOG("Overall time for sampling all instances: " << watch << std::endl << std::endl);
  415. }
  416. }
  417. template <typename ValueType, typename SolveValueType = double>
  418. void verifyPropertiesAtSamplePoints(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, SampleInformation<ValueType> const& samples) {
  419. if (model->isOfType(storm::models::ModelType::Dtmc)) {
  420. verifyPropertiesAtSamplePoints<storm::modelchecker::SparseDtmcInstantiationModelChecker, storm::models::sparse::Dtmc<ValueType>, ValueType, SolveValueType>(*model->template as<storm::models::sparse::Dtmc<ValueType>>(), input, samples);
  421. } else if (model->isOfType(storm::models::ModelType::Ctmc)) {
  422. verifyPropertiesAtSamplePoints<storm::modelchecker::SparseCtmcInstantiationModelChecker, storm::models::sparse::Ctmc<ValueType>, ValueType, SolveValueType>(*model->template as<storm::models::sparse::Ctmc<ValueType>>(), input, samples);
  423. } else if (model->isOfType(storm::models::ModelType::Mdp)) {
  424. verifyPropertiesAtSamplePoints<storm::modelchecker::SparseMdpInstantiationModelChecker, storm::models::sparse::Mdp<ValueType>, ValueType, SolveValueType>(*model->template as<storm::models::sparse::Mdp<ValueType>>(), input, samples);
  425. } else {
  426. STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs, CTMCs and MDPs.");
  427. }
  428. }
  429. template <typename ValueType>
  430. void verifyPropertiesWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, SampleInformation<ValueType> const& samples) {
  431. if (samples.empty()) {
  432. verifyProperties<ValueType>(input.properties,
  433. [&model] (std::shared_ptr<storm::logic::Formula const> const& formula) {
  434. std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(formula, true));
  435. if (result) {
  436. result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
  437. }
  438. return result;
  439. },
  440. [&model] (std::unique_ptr<storm::modelchecker::CheckResult> const& result) {
  441. auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>();
  442. if (parametricSettings.exportResultToFile() && model->isOfType(storm::models::ModelType::Dtmc)) {
  443. auto dtmc = model->template as<storm::models::sparse::Dtmc<ValueType>>();
  444. boost::optional<ValueType> rationalFunction = result->asExplicitQuantitativeCheckResult<ValueType>()[*model->getInitialStates().begin()];
  445. storm::api::exportParametricResultToFile(rationalFunction, storm::analysis::ConstraintCollector<ValueType>(*dtmc), parametricSettings.exportResultPath());
  446. }
  447. else if (parametricSettings.exportResultToFile() && model->isOfType(storm::models::ModelType::Ctmc)) {
  448. auto ctmc = model->template as<storm::models::sparse::Ctmc<ValueType>>();
  449. boost::optional<ValueType> rationalFunction = result->asExplicitQuantitativeCheckResult<ValueType>()[*model->getInitialStates().begin()];
  450. storm::api::exportParametricResultToFile(rationalFunction, storm::analysis::ConstraintCollector<ValueType>(*ctmc), parametricSettings.exportResultPath());
  451. }
  452. });
  453. } else {
  454. STORM_LOG_TRACE("Sampling the model at given points.");
  455. if (samples.exact) {
  456. verifyPropertiesAtSamplePoints<ValueType, storm::RationalNumber>(model, input, samples);
  457. } else {
  458. verifyPropertiesAtSamplePoints<ValueType, double>(model, input, samples);
  459. }
  460. }
  461. }
  462. template <typename ValueType>
  463. void analyzeMonotonicity(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions) {
  464. std::ofstream outfile;
  465. auto monSettings = storm::settings::getModule<storm::settings::modules::MonotonicitySettings>();
  466. if (monSettings.isExportMonotonicitySet()) {
  467. utility::openFile(monSettings.getExportMonotonicityFilename(), outfile);
  468. }
  469. std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::api::extractFormulasFromProperties(input.properties);
  470. storm::utility::Stopwatch monotonicityWatch(true);
  471. STORM_LOG_THROW(regions.size() <= 1, storm::exceptions::InvalidArgumentException, "Monotonicity analysis only allowed on single region");
  472. if (!monSettings.isMonSolutionSet()) {
  473. auto monotonicityHelper = storm::analysis::MonotonicityHelper<ValueType, double>(model, formulas, regions, monSettings.getNumberOfSamples(), storm::settings::getModule<storm::settings::modules::GeneralSettings>().getPrecision(), monSettings.isDotOutputSet());
  474. if (monSettings.isExportMonotonicitySet()) {
  475. monotonicityHelper.checkMonotonicityInBuild(outfile, monSettings.isUsePLABoundsSet(), monSettings.getDotOutputFilename());
  476. } else {
  477. monotonicityHelper.checkMonotonicityInBuild(std::cout, monSettings.isUsePLABoundsSet(), monSettings.getDotOutputFilename());
  478. }
  479. } else {
  480. // Checking monotonicity based on solution function
  481. auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>();
  482. auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>();
  483. std::function<std::unique_ptr<storm::modelchecker::CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula)> verificationCallback;
  484. std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)> postprocessingCallback;
  485. // Check the given set of regions with or without refinement
  486. verificationCallback = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) {
  487. std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(formula, true));
  488. return result;
  489. };
  490. for (auto & property : input.properties) {
  491. auto result = verificationCallback(property.getRawFormula())->asExplicitQuantitativeCheckResult<ValueType>().getValueVector();
  492. ValueType valuation;
  493. auto states= model->getInitialStates();
  494. for (auto state : states) {
  495. valuation += result[state];
  496. }
  497. storm::analysis::MonotonicityResult<storm::RationalFunctionVariable> monRes;
  498. for (auto & var : storm::models::sparse::getProbabilityParameters(*model)) {
  499. auto res = storm::analysis::MonotonicityChecker<ValueType>::checkDerivative(valuation.derivative(var), regions[0]);
  500. if (res.first && res.second) {
  501. monRes.addMonotonicityResult(var, analysis::MonotonicityResult<storm::RationalFunctionVariable>::Monotonicity::Constant);
  502. } else if (res.first) {
  503. monRes.addMonotonicityResult(var, analysis::MonotonicityResult<storm::RationalFunctionVariable>::Monotonicity::Incr);
  504. } else if (res.second) {
  505. monRes.addMonotonicityResult(var, analysis::MonotonicityResult<storm::RationalFunctionVariable>::Monotonicity::Decr);
  506. } else {
  507. monRes.addMonotonicityResult(var, analysis::MonotonicityResult<storm::RationalFunctionVariable>::Monotonicity::Not);
  508. }
  509. }
  510. if (monSettings.isExportMonotonicitySet()) {
  511. outfile << monRes.toString();
  512. } else {
  513. STORM_PRINT(monRes.toString());
  514. }
  515. }
  516. }
  517. if (monSettings.isExportMonotonicitySet()) {
  518. utility::closeFile(outfile);
  519. }
  520. monotonicityWatch.stop();
  521. STORM_PRINT(std::endl << "Total time for monotonicity checking: " << monotonicityWatch << "." << std::endl << std::endl);
  522. return;
  523. }
  524. template <typename ValueType>
  525. void computeRegionExtremumWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions, storm::api::MonotonicitySetting monotonicitySettings = storm::api::MonotonicitySetting(), boost::optional<std::pair<std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType>, std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType>>>& monotoneParameters = boost::none) {
  526. STORM_LOG_ASSERT(!regions.empty(), "Can not analyze an empty set of regions.");
  527. auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>();
  528. auto monSettings = storm::settings::getModule<storm::settings::modules::MonotonicitySettings>();
  529. auto engine = regionSettings.getRegionCheckEngine();
  530. storm::solver::OptimizationDirection direction = regionSettings.getExtremumDirection();
  531. ValueType precision = storm::utility::convertNumber<ValueType>(regionSettings.getExtremumValuePrecision());
  532. bool generateSplitEstimates = regionSettings.isSplittingThresholdSet();
  533. for (auto const& property : input.properties) {
  534. for (auto const& region : regions) {
  535. if (monotonicitySettings.useMonotonicity) {
  536. STORM_PRINT_AND_LOG("Computing extremal value for property " << property.getName() << ": "
  537. << *property.getRawFormula()
  538. << " within region " << region
  539. << " and using monotonicity ..." << std::endl);
  540. } else {
  541. STORM_PRINT_AND_LOG("Computing extremal value for property " << property.getName() << ": "
  542. << *property.getRawFormula()
  543. << " within region " << region
  544. << "..." << std::endl);
  545. }
  546. storm::utility::Stopwatch watch(true);
  547. // TODO: hier eventueel checkExtremalValue van maken
  548. if (regionSettings.isExtremumSuggestionSet()) {
  549. ValueType suggestion = storm::utility::convertNumber<ValueType>(regionSettings.getExtremumSuggestion());
  550. if (storm::api::checkExtremalValue<ValueType>(model, storm::api::createTask<ValueType>(property.getRawFormula(), true), region, engine, direction, precision, suggestion, monotonicitySettings, generateSplitEstimates, monotoneParameters)) {
  551. STORM_PRINT_AND_LOG(suggestion << " is the extremum ");
  552. } else {
  553. STORM_PRINT_AND_LOG(suggestion << " is NOT the extremum ");
  554. }
  555. } else {
  556. auto valueValuation = storm::api::computeExtremalValue<ValueType>(model, storm::api::createTask<ValueType>(property.getRawFormula(), true), region, engine, direction, precision, monotonicitySettings, generateSplitEstimates, monotoneParameters);
  557. watch.stop();
  558. std::stringstream valuationStr;
  559. bool first = true;
  560. for (auto const& v : valueValuation.second) {
  561. if (first) {
  562. first = false;
  563. } else {
  564. valuationStr << ", ";
  565. }
  566. valuationStr << v.first << "=" << v.second;
  567. }
  568. STORM_PRINT_AND_LOG("Result at initial state: " << valueValuation.first << " ( approx. " << storm::utility::convertNumber<double>(valueValuation.first) << ") at [" << valuationStr.str() << "]." << std::endl)
  569. STORM_PRINT_AND_LOG("Time for model checking: " << watch << "." << std::endl);
  570. }
  571. }
  572. }
  573. }
  574. template <typename ValueType>
  575. void verifyRegionsWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions, storm::api::MonotonicitySetting monotonicitySettings = storm::api::MonotonicitySetting(), uint64_t monThresh = 0) {
  576. STORM_LOG_ASSERT(!regions.empty(), "Can not analyze an empty set of regions.");
  577. auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>();
  578. auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>();
  579. std::function<std::unique_ptr<storm::modelchecker::CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula)> verificationCallback;
  580. std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)> postprocessingCallback;
  581. STORM_PRINT_AND_LOG(std::endl);
  582. if (regionSettings.isHypothesisSet()) {
  583. STORM_PRINT_AND_LOG("Checking hypothesis " << regionSettings.getHypothesis() << " on ");
  584. } else {
  585. STORM_PRINT_AND_LOG("Analyzing ");
  586. }
  587. if (regions.size() == 1) {
  588. STORM_PRINT_AND_LOG("parameter region " << regions.front());
  589. } else {
  590. STORM_PRINT_AND_LOG(regions.size() << " parameter regions");
  591. }
  592. auto engine = regionSettings.getRegionCheckEngine();
  593. STORM_PRINT_AND_LOG(" using " << engine);
  594. if (monotonicitySettings.useMonotonicity) {
  595. STORM_PRINT_AND_LOG(" with local monotonicity and");
  596. }
  597. // Check the given set of regions with or without refinement
  598. if (regionSettings.isRefineSet()) {
  599. STORM_LOG_THROW(regions.size() == 1, storm::exceptions::NotSupportedException, "Region refinement is not supported for multiple initial regions.");
  600. STORM_PRINT_AND_LOG(" with iterative refinement until " << (1.0 - regionSettings.getCoverageThreshold()) * 100.0 << "% is covered." << (regionSettings.isDepthLimitSet() ? " Depth limit is " + std::to_string(regionSettings.getDepthLimit()) + "." : "") << std::endl);
  601. verificationCallback = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) {
  602. ValueType refinementThreshold = storm::utility::convertNumber<ValueType>(regionSettings.getCoverageThreshold());
  603. boost::optional<uint64_t> optionalDepthLimit;
  604. if (regionSettings.isDepthLimitSet()) {
  605. optionalDepthLimit = regionSettings.getDepthLimit();
  606. }
  607. // TODO @Jip: change allow model simplification when not using monotonicity, for benchmarking purposes simplification is moved forward.
  608. std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ValueType>> result = storm::api::checkAndRefineRegionWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(formula, true), regions.front(), engine, refinementThreshold, optionalDepthLimit, regionSettings.getHypothesis(), false, monotonicitySettings, monThresh);
  609. return result;
  610. };
  611. } else {
  612. STORM_PRINT_AND_LOG("." << std::endl);
  613. verificationCallback = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) {
  614. std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::checkRegionsWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(formula, true), regions, engine, regionSettings.getHypothesis());
  615. return result;
  616. };
  617. }
  618. postprocessingCallback = [&] (std::unique_ptr<storm::modelchecker::CheckResult> const& result) {
  619. if (parametricSettings.exportResultToFile()) {
  620. storm::api::exportRegionCheckResultToFile<ValueType>(result, parametricSettings.exportResultPath());
  621. }
  622. };
  623. verifyProperties<ValueType>(input.properties, verificationCallback, postprocessingCallback);
  624. }
  625. template <typename ValueType>
  626. void verifyWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions, SampleInformation<ValueType> const& samples, storm::api::MonotonicitySetting monotonicitySettings = storm::api::MonotonicitySetting(), boost::optional<std::pair<std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType>, std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType>>>& monotoneParameters = boost::none, uint64_t monThresh = 0) {
  627. if (regions.empty()) {
  628. storm::pars::verifyPropertiesWithSparseEngine(model, input, samples);
  629. } else {
  630. auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>();
  631. auto monSettings = storm::settings::getModule<storm::settings::modules::MonotonicitySettings>();
  632. if (monSettings.isMonotonicityAnalysisSet()) {
  633. storm::pars::analyzeMonotonicity(model, input, regions);
  634. } else if (regionSettings.isExtremumSet()) {
  635. storm::pars::computeRegionExtremumWithSparseEngine(model, input, regions, monotonicitySettings, monotoneParameters);
  636. } else {
  637. assert (monotoneParameters == boost::none);
  638. assert (!monotonicitySettings.useOnlyGlobalMonotonicity);
  639. assert (!monotonicitySettings.useBoundsFromPLA);
  640. storm::pars::verifyRegionsWithSparseEngine(model, input, regions, monotonicitySettings, monThresh);
  641. }
  642. }
  643. }
  644. template <storm::dd::DdType DdType, typename ValueType>
  645. void verifyPropertiesWithSymbolicEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input, SampleInformation<ValueType> const& samples) {
  646. if (samples.empty()) {
  647. verifyProperties<ValueType>(input.properties,
  648. [&model] (std::shared_ptr<storm::logic::Formula const> const& formula) {
  649. std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithDdEngine<DdType, ValueType>(model, storm::api::createTask<ValueType>(formula, true));
  650. if (result) {
  651. result->filter(storm::modelchecker::SymbolicQualitativeCheckResult<DdType>(model->getReachableStates(), model->getInitialStates()));
  652. }
  653. return result;
  654. },
  655. [&model] (std::unique_ptr<storm::modelchecker::CheckResult> const& result) {
  656. auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>();
  657. if (parametricSettings.exportResultToFile() && model->isOfType(storm::models::ModelType::Dtmc)) {
  658. //auto dtmc = model->template as<storm::models::symbolic::Dtmc<DdType, ValueType>>();
  659. //boost::optional<ValueType> rationalFunction = result->asSymbolicQuantitativeCheckResult<DdType, ValueType>().sum();
  660. //storm::api::exportParametricResultToFile(rationalFunction, storm::analysis::ConstraintCollector<ValueType>(*dtmc), parametricSettings.exportResultPath());
  661. }
  662. });
  663. } else {
  664. STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is not supported in the symbolic engine.");
  665. }
  666. }
  667. template <storm::dd::DdType DdType, typename ValueType>
  668. void verifyWithDdEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions, SampleInformation<ValueType> const& samples) {
  669. if (regions.empty()) {
  670. storm::pars::verifyPropertiesWithSymbolicEngine(model, input, samples);
  671. } else {
  672. STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Region verification is not supported in the symbolic engine.");
  673. }
  674. }
  675. template <storm::dd::DdType DdType, typename ValueType>
  676. void verifyParametricModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions, SampleInformation<ValueType> const& samples, storm::api::MonotonicitySetting monotonicitySettings = storm::api::MonotonicitySetting(), boost::optional<std::pair<std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType>, std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType>>>& monotoneParameters = boost::none, uint64_t monThresh = 0) {
  677. if (model->isSparseModel()) {
  678. storm::pars::verifyWithSparseEngine<ValueType>(model->as<storm::models::sparse::Model<ValueType>>(), input, regions, samples, monotonicitySettings, monotoneParameters, monThresh);
  679. } else {
  680. assert (!monotonicitySettings.useMonotonicity);
  681. assert (monotoneParameters == boost::none);
  682. storm::pars::verifyWithDdEngine<DdType, ValueType>(model->as<storm::models::symbolic::Model<DdType, ValueType>>(), input, regions, samples);
  683. }
  684. }
  685. template <storm::dd::DdType DdType, typename ValueType>
  686. void processInputWithValueTypeAndDdlib(SymbolicInput& input, storm::cli::ModelProcessingInformation const& mpi) {
  687. auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
  688. auto buildSettings = storm::settings::getModule<storm::settings::modules::BuildSettings>();
  689. auto parSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>();
  690. auto monSettings = storm::settings::getModule<storm::settings::modules::MonotonicitySettings>();
  691. STORM_LOG_THROW(mpi.engine == storm::utility::Engine::Sparse || mpi.engine == storm::utility::Engine::Hybrid || mpi.engine == storm::utility::Engine::Dd, storm::exceptions::InvalidSettingsException, "The selected engine is not supported for parametric models.");
  692. std::shared_ptr<storm::models::ModelBase> model;
  693. if (!buildSettings.isNoBuildModelSet()) {
  694. model = storm::cli::buildModel<DdType, ValueType>(input, ioSettings, mpi);
  695. }
  696. if (model) {
  697. model->printModelInformationToStream(std::cout);
  698. }
  699. STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model.");
  700. if (model) {
  701. auto preprocessingResult = storm::pars::preprocessModel<DdType, ValueType>(model, input, mpi);
  702. if (preprocessingResult.changed) {
  703. model = preprocessingResult.model;
  704. if (preprocessingResult.formulas) {
  705. std::vector<storm::jani::Property> newProperties;
  706. for (size_t i = 0; i < preprocessingResult.formulas.get().size(); ++i) {
  707. auto formula = preprocessingResult.formulas.get().at(i);
  708. STORM_LOG_ASSERT(i < input.properties.size(), "Index " << i << " greater than number of properties.");
  709. storm::jani::Property property = input.properties.at(i);
  710. newProperties.push_back(storm::jani::Property(property.getName(), formula, property.getUndefinedConstants(), nullptr, property.getComment()));
  711. }
  712. input.properties = newProperties;
  713. }
  714. model->printModelInformationToStream(std::cout);
  715. }
  716. }
  717. std::vector<storm::storage::ParameterRegion<ValueType>> regions = parseRegions<ValueType>(model);
  718. std::string samplesAsString = parSettings.getSamples();
  719. SampleInformation<ValueType> samples;
  720. if (!samplesAsString.empty()) {
  721. samples = parseSamples<ValueType>(model, samplesAsString,
  722. parSettings.isSamplesAreGraphPreservingSet());
  723. samples.exact = parSettings.isSampleExactSet();
  724. }
  725. if (model) {
  726. storm::cli::exportModel<DdType, ValueType>(model, input);
  727. }
  728. if (parSettings.onlyObtainConstraints()) {
  729. STORM_LOG_THROW(parSettings.exportResultToFile(), storm::exceptions::InvalidSettingsException,
  730. "When computing constraints, export path has to be specified.");
  731. storm::api::exportParametricResultToFile<ValueType>(boost::none,
  732. storm::analysis::ConstraintCollector<ValueType>(
  733. *(model->as<storm::models::sparse::Model<ValueType>>())),
  734. parSettings.exportResultPath());
  735. return;
  736. }
  737. if (model) {
  738. boost::optional<std::pair<std::set<storm::RationalFunctionVariable>, std::set<storm::RationalFunctionVariable>>> monotoneParameters;
  739. if (monSettings.isMonotoneParametersSet()) {
  740. monotoneParameters = std::move(
  741. storm::api::parseMonotoneParameters<ValueType>(monSettings.getMonotoneParameterFilename(),
  742. model->as<storm::models::sparse::Model<ValueType>>()));
  743. }
  744. // TODO: is onlyGlobalSet was used here
  745. verifyParametricModel<DdType, ValueType>(model, input, regions, samples, storm::api::MonotonicitySetting(parSettings.isUseMonotonicitySet(), false, monSettings.isUsePLABoundsSet()), monotoneParameters, monSettings.getMonotonicityThreshold());
  746. }
  747. }
  748. void processOptions() {
  749. // Start by setting some urgent options (log levels, resources, etc.)
  750. storm::cli::setUrgentOptions();
  751. auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>();
  752. auto engine = coreSettings.getEngine();
  753. STORM_LOG_WARN_COND(engine != storm::utility::Engine::Dd || engine != storm::utility::Engine::Hybrid || coreSettings.getDdLibraryType() == storm::dd::DdType::Sylvan, "The selected DD library does not support parametric models. Switching to Sylvan...");
  754. // Parse and preprocess symbolic input (PRISM, JANI, properties, etc.)
  755. auto symbolicInput = storm::cli::parseSymbolicInput();
  756. storm::cli::ModelProcessingInformation mpi;
  757. std::tie(symbolicInput, mpi) = storm::cli::preprocessSymbolicInput(symbolicInput);
  758. processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, storm::RationalFunction>(symbolicInput, mpi);
  759. }
  760. }
  761. }
  762. /*!
  763. * Main entry point of the executable storm-pars.
  764. */
  765. int main(const int argc, const char** argv) {
  766. try {
  767. storm::utility::setUp();
  768. storm::cli::printHeader("Storm-pars", argc, argv);
  769. storm::settings::initializeParsSettings("Storm-pars", "storm-pars");
  770. storm::utility::Stopwatch totalTimer(true);
  771. if (!storm::cli::parseOptions(argc, argv)) {
  772. return -1;
  773. }
  774. storm::pars::processOptions();
  775. totalTimer.stop();
  776. if (storm::settings::getModule<storm::settings::modules::ResourceSettings>().isPrintTimeAndMemorySet()) {
  777. storm::cli::printTimeAndMemoryStatistics(totalTimer.getTimeInMilliseconds());
  778. }
  779. storm::utility::cleanUp();
  780. return 0;
  781. } catch (storm::exceptions::BaseException const& exception) {
  782. STORM_LOG_ERROR("An exception caused Storm-pars to terminate. The message of the exception is: " << exception.what());
  783. return 1;
  784. } catch (std::exception const& exception) {
  785. STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-pars to terminate. The message of this exception is: " << exception.what());
  786. return 2;
  787. }
  788. }