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.

567 lines
38 KiB

  1. #include "src/modelchecker/region/SparseRegionModelChecker.h"
  2. #include "src/adapters/CarlAdapter.h"
  3. #include "src/modelchecker/region/RegionCheckResult.h"
  4. #include "src/modelchecker/results/ExplicitQuantitativeCheckResult.h"
  5. #include "src/logic/Formulas.h"
  6. #include "src/models/sparse/StandardRewardModel.h"
  7. #include "src/settings/SettingsManager.h"
  8. #include "src/settings/modules/RegionSettings.h"
  9. #include "src/utility/constants.h"
  10. #include "src/utility/graph.h"
  11. #include "src/utility/macros.h"
  12. #include "src/exceptions/InvalidArgumentException.h"
  13. #include "src/exceptions/InvalidPropertyException.h"
  14. #include "src/exceptions/InvalidStateException.h"
  15. #include "src/exceptions/InvalidSettingsException.h"
  16. #include "src/exceptions/NotImplementedException.h"
  17. #include "src/exceptions/UnexpectedException.h"
  18. #include "modelchecker/results/CheckResult.h"
  19. #include "modelchecker/results/ExplicitQuantitativeCheckResult.h"
  20. namespace storm {
  21. namespace modelchecker {
  22. namespace region {
  23. SparseRegionModelCheckerSettings::SparseRegionModelCheckerSettings(storm::settings::modules::RegionSettings::SampleMode const& sampleM,
  24. storm::settings::modules::RegionSettings::ApproxMode const& appM,
  25. storm::settings::modules::RegionSettings::SmtMode const& smtM) : sampleMode(sampleM), approxMode(appM), smtMode(smtM) {
  26. // Intentionally left empty
  27. }
  28. storm::settings::modules::RegionSettings::ApproxMode SparseRegionModelCheckerSettings::getApproxMode() const {
  29. return this->approxMode;
  30. }
  31. storm::settings::modules::RegionSettings::SampleMode SparseRegionModelCheckerSettings::getSampleMode() const {
  32. return this->sampleMode;
  33. }
  34. storm::settings::modules::RegionSettings::SmtMode SparseRegionModelCheckerSettings::getSmtMode() const {
  35. return this->smtMode;
  36. }
  37. bool SparseRegionModelCheckerSettings::doApprox() const {
  38. return getApproxMode() != storm::settings::modules::RegionSettings::ApproxMode::OFF;
  39. }
  40. bool SparseRegionModelCheckerSettings::doSample() const {
  41. return getSampleMode() != storm::settings::modules::RegionSettings::SampleMode::OFF;
  42. }
  43. bool SparseRegionModelCheckerSettings::doSmt() const {
  44. return getSmtMode() != storm::settings::modules::RegionSettings::SmtMode::OFF;
  45. }
  46. template<typename ParametricSparseModelType, typename ConstantType>
  47. SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::SparseRegionModelChecker(std::shared_ptr<ParametricSparseModelType> model, SparseRegionModelCheckerSettings const& settings) :
  48. model(model),
  49. specifiedFormula(nullptr),
  50. settings(settings) {
  51. STORM_LOG_THROW(model->getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::InvalidArgumentException, "Model is required to have exactly one initial state.");
  52. }
  53. template<typename ParametricSparseModelType, typename ConstantType>
  54. SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::~SparseRegionModelChecker() {
  55. //Intentionally left empty
  56. }
  57. template<typename ParametricSparseModelType, typename ConstantType>
  58. std::shared_ptr<ParametricSparseModelType> const& SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::getModel() const {
  59. return this->model;
  60. }
  61. template<typename ParametricSparseModelType, typename ConstantType>
  62. std::shared_ptr<storm::logic::OperatorFormula> const& SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::getSpecifiedFormula() const {
  63. return this->specifiedFormula;
  64. }
  65. template<typename ParametricSparseModelType, typename ConstantType>
  66. ConstantType SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::getSpecifiedFormulaBound() const {
  67. return storm::utility::region::convertNumber<ConstantType>(this->getSpecifiedFormula()->getThreshold());
  68. }
  69. template<typename ParametricSparseModelType, typename ConstantType>
  70. bool SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::specifiedFormulaHasLowerBound() const {
  71. return storm::logic::isLowerBound(this->getSpecifiedFormula()->getComparisonType());
  72. }
  73. template<typename ParametricSparseModelType, typename ConstantType>
  74. bool const& SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::isComputeRewards() const {
  75. return computeRewards;
  76. }
  77. template<typename ParametricSparseModelType, typename ConstantType>
  78. bool const SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::isResultConstant() const {
  79. return this->constantResult.operator bool();
  80. }
  81. template<typename ParametricSparseModelType, typename ConstantType>
  82. std::shared_ptr<ParametricSparseModelType> const& SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::getSimpleModel() const {
  83. return this->simpleModel;
  84. }
  85. template<typename ParametricSparseModelType, typename ConstantType>
  86. std::shared_ptr<storm::logic::OperatorFormula> const& SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::getSimpleFormula() const {
  87. return this->simpleFormula;
  88. }
  89. // template<typename ParametricSparseModelType, typename ConstantType>
  90. // SparseRegionModelCheckerSettings& SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::getSettings() {
  91. // return this->settings;
  92. // };
  93. template<typename ParametricSparseModelType, typename ConstantType>
  94. SparseRegionModelCheckerSettings const& SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::getSettings() const {
  95. return this->settings;
  96. };
  97. template<typename ParametricSparseModelType, typename ConstantType>
  98. void SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::specifyFormula(std::shared_ptr<const storm::logic::Formula> formula) {
  99. std::chrono::high_resolution_clock::time_point timeSpecifyFormulaStart = std::chrono::high_resolution_clock::now();
  100. STORM_LOG_DEBUG("Specifying the formula " << *formula.get());
  101. STORM_LOG_THROW(this->canHandle(*formula), storm::exceptions::InvalidArgumentException, "Tried to specify a formula that can not be handled.");
  102. //Initialize the context for this formula
  103. if (formula->isProbabilityOperatorFormula()) {
  104. this->specifiedFormula = std::make_shared<storm::logic::ProbabilityOperatorFormula>(formula->asProbabilityOperatorFormula());
  105. this->computeRewards = false;
  106. }
  107. else if (formula->isRewardOperatorFormula()) {
  108. this->specifiedFormula = std::make_shared<storm::logic::RewardOperatorFormula>(formula->asRewardOperatorFormula());
  109. this->computeRewards=true;
  110. }
  111. else {
  112. STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The specified property " << this->getSpecifiedFormula() << "is not supported");
  113. }
  114. this->constantResult = boost::none;
  115. this->simpleFormula = nullptr;
  116. this->isApproximationApplicable = false;
  117. this->approximationModel = nullptr;
  118. this->samplingModel = nullptr;
  119. //stuff for statistics:
  120. this->numOfCheckedRegions=0;
  121. this->numOfRegionsSolvedThroughSampling=0;
  122. this->numOfRegionsSolvedThroughApproximation=0;
  123. this->numOfRegionsSolvedThroughSmt=0;
  124. this->numOfRegionsExistsBoth=0;
  125. this->numOfRegionsAllSat=0;
  126. this->numOfRegionsAllViolated=0;
  127. this->timeCheckRegion=std::chrono::high_resolution_clock::duration::zero();
  128. this->timeSampling=std::chrono::high_resolution_clock::duration::zero();
  129. this->timeApproximation=std::chrono::high_resolution_clock::duration::zero();
  130. this->timeSmt=std::chrono::high_resolution_clock::duration::zero();
  131. this->timeComputeReachabilityFunction=std::chrono::high_resolution_clock::duration::zero();
  132. std::chrono::high_resolution_clock::time_point timePreprocessingStart = std::chrono::high_resolution_clock::now();
  133. this->preprocess(this->simpleModel, this->simpleFormula, isApproximationApplicable, constantResult);
  134. std::chrono::high_resolution_clock::time_point timePreprocessingEnd = std::chrono::high_resolution_clock::now();
  135. //TODO: Currently we are not able to detect functions of the form p*q correctly as these functions are not linear but approximation is still applicable.
  136. //This is just a quick fix to work with such models anyway.
  137. if(!this->isApproximationApplicable){
  138. STORM_LOG_ERROR("There are non-linear functions that occur in the given model. Approximation is still correct for functions that are linear w.r.t. a single parameter (assuming the remaining parameters are constants), e.g., p*q is okay. Currently, the implementation is not able to validate this..");
  139. this->isApproximationApplicable=true;
  140. }
  141. //Check if the approximation and the sampling model needs to be computed
  142. if(!this->isResultConstant()){
  143. if(this->isApproximationApplicable && settings.doApprox()){
  144. initializeApproximationModel(*this->getSimpleModel(), this->getSimpleFormula());
  145. }
  146. if(settings.getSampleMode()==storm::settings::modules::RegionSettings::SampleMode::INSTANTIATE ||
  147. (!settings.doSample() && settings.getApproxMode()==storm::settings::modules::RegionSettings::ApproxMode::TESTFIRST)){
  148. initializeSamplingModel(*this->getSimpleModel(), this->getSimpleFormula());
  149. }
  150. } else if (this->isResultConstant() && this->constantResult.get() == storm::utility::region::convertNumber<ConstantType>(-1.0)){
  151. //In this case, the result is constant but has not been computed yet. so do it now!
  152. STORM_LOG_DEBUG("The Result is constant and will be computed now.");
  153. initializeSamplingModel(*this->getSimpleModel(), this->getSimpleFormula());
  154. std::map<VariableType, CoefficientType> emptySubstitution;
  155. this->constantResult = this->getSamplingModel()->computeInitialStateValue(emptySubstitution);
  156. }
  157. //some more information for statistics...
  158. std::chrono::high_resolution_clock::time_point timeSpecifyFormulaEnd = std::chrono::high_resolution_clock::now();
  159. this->timeSpecifyFormula= timeSpecifyFormulaEnd - timeSpecifyFormulaStart;
  160. this->timePreprocessing = timePreprocessingEnd - timePreprocessingStart;
  161. }
  162. template<typename ParametricSparseModelType, typename ConstantType>
  163. void SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::initializeApproximationModel(ParametricSparseModelType const& model, std::shared_ptr<storm::logic::OperatorFormula> formula) {
  164. std::chrono::high_resolution_clock::time_point timeInitApproxModelStart = std::chrono::high_resolution_clock::now();
  165. STORM_LOG_DEBUG("Initializing the Approximation Model...");
  166. STORM_LOG_THROW(this->isApproximationApplicable, storm::exceptions::UnexpectedException, "Approximation model requested but approximation is not applicable");
  167. this->approximationModel=std::make_shared<ApproximationModel<ParametricSparseModelType, ConstantType>>(model, formula);
  168. std::chrono::high_resolution_clock::time_point timeInitApproxModelEnd = std::chrono::high_resolution_clock::now();
  169. this->timeInitApproxModel=timeInitApproxModelEnd - timeInitApproxModelStart;
  170. STORM_LOG_DEBUG("Initialized Approximation Model");
  171. }
  172. template<typename ParametricSparseModelType, typename ConstantType>
  173. void SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::initializeSamplingModel(ParametricSparseModelType const& model, std::shared_ptr<storm::logic::OperatorFormula> formula) {
  174. STORM_LOG_DEBUG("Initializing the Sampling Model....");
  175. std::chrono::high_resolution_clock::time_point timeInitSamplingModelStart = std::chrono::high_resolution_clock::now();
  176. this->samplingModel=std::make_shared<SamplingModel<ParametricSparseModelType, ConstantType>>(model, formula);
  177. std::chrono::high_resolution_clock::time_point timeInitSamplingModelEnd = std::chrono::high_resolution_clock::now();
  178. this->timeInitSamplingModel = timeInitSamplingModelEnd - timeInitSamplingModelStart;
  179. STORM_LOG_DEBUG("Initialized Sampling Model");
  180. }
  181. template<typename ParametricSparseModelType, typename ConstantType>
  182. void SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::checkRegions(std::vector<ParameterRegion<ParametricType>>& regions) {
  183. STORM_LOG_DEBUG("Checking " << regions.size() << "regions.");
  184. std::cout << "Checking " << regions.size() << " regions. Progress: ";
  185. std::cout.flush();
  186. uint_fast64_t progress=0;
  187. uint_fast64_t checkedRegions=0;
  188. for(auto& region : regions){
  189. this->checkRegion(region);
  190. if((checkedRegions++)*10/regions.size()==progress){
  191. std::cout << progress++;
  192. std::cout.flush();
  193. }
  194. }
  195. std::cout << " done!" << std::endl;
  196. }
  197. template<typename ParametricSparseModelType, typename ConstantType>
  198. void SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::refineAndCheckRegion(std::vector<ParameterRegion<ParametricType>>& regions, double const& refinementThreshold) {
  199. STORM_LOG_DEBUG("Applying refinement on region: " << regions.front().toString() << ".");
  200. std::cout << "Applying refinement on region: " << regions.front().toString() << std::endl;
  201. std::cout.flush();
  202. CoefficientType areaOfParameterSpace = regions.front().area();
  203. uint_fast64_t indexOfCurrentRegion=0;
  204. CoefficientType fractionOfUndiscoveredArea = storm::utility::one<CoefficientType>();
  205. CoefficientType fractionOfAllSatArea = storm::utility::zero<CoefficientType>();
  206. CoefficientType fractionOfAllViolatedArea = storm::utility::zero<CoefficientType>();
  207. while(fractionOfUndiscoveredArea > storm::utility::region::convertNumber<CoefficientType>(refinementThreshold)){
  208. STORM_LOG_THROW(indexOfCurrentRegion < regions.size(), storm::exceptions::InvalidStateException, "Threshold for undiscovered area not reached but no unprocessed regions left.");
  209. ParameterRegion<ParametricType>& currentRegion = regions[indexOfCurrentRegion];
  210. this->checkRegion(currentRegion);
  211. switch(currentRegion.getCheckResult()){
  212. case RegionCheckResult::ALLSAT:
  213. fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace;
  214. fractionOfAllSatArea += currentRegion.area() / areaOfParameterSpace;
  215. break;
  216. case RegionCheckResult::ALLVIOLATED:
  217. fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace;
  218. fractionOfAllViolatedArea += currentRegion.area() / areaOfParameterSpace;
  219. break;
  220. default:
  221. std::vector<ParameterRegion<ParametricType>> newRegions;
  222. currentRegion.split(currentRegion.getCenterPoint(), newRegions);
  223. regions.insert(regions.end(), newRegions.begin(), newRegions.end());
  224. break;
  225. }
  226. ++indexOfCurrentRegion;
  227. }
  228. std::cout << " done! " << std::endl << "Fraction of ALLSAT;ALLVIOLATED;UNDISCOVERED area:" << std::endl;
  229. std::cout << "REFINEMENTRESULT;" <<storm::utility::region::convertNumber<double>(fractionOfAllSatArea) << ";" << storm::utility::region::convertNumber<double>(fractionOfAllViolatedArea) << ";" << storm::utility::region::convertNumber<double>(fractionOfUndiscoveredArea) << std::endl;
  230. }
  231. template<typename ParametricSparseModelType, typename ConstantType>
  232. void SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::checkRegion(ParameterRegion<ParametricType>& region) {
  233. std::chrono::high_resolution_clock::time_point timeCheckRegionStart = std::chrono::high_resolution_clock::now();
  234. ++this->numOfCheckedRegions;
  235. STORM_LOG_THROW(this->getSpecifiedFormula()!=nullptr, storm::exceptions::InvalidStateException, "Tried to analyze a region although no property has been specified" );
  236. STORM_LOG_DEBUG("Analyzing the region " << region.toString());
  237. //switches for the different steps.
  238. bool done=false;
  239. STORM_LOG_WARN_COND( (!settings.doApprox() || this->isApproximationApplicable), "the approximation is only correct if the model has only linear functions (more precisely: linear in a single parameter, i.e., functions like p*q are okay). As this is not the case, approximation is deactivated");
  240. bool doApproximation=settings.doApprox() && this->isApproximationApplicable;
  241. bool doSampling=settings.doSample();
  242. bool doSmt=settings.doSmt();
  243. if(this->isResultConstant()){
  244. STORM_LOG_DEBUG("Checking a region although the result is constant, i.e., independent of the region. This makes sense none.");
  245. if(this->checkFormulaOnSamplingPoint(region.getSomePoint())){
  246. region.setCheckResult(RegionCheckResult::ALLSAT);
  247. }
  248. else{
  249. region.setCheckResult(RegionCheckResult::ALLVIOLATED);
  250. }
  251. done=true;
  252. }
  253. std::chrono::high_resolution_clock::time_point timeApproximationStart = std::chrono::high_resolution_clock::now();
  254. if(!done && doApproximation){
  255. STORM_LOG_DEBUG("Checking approximative values...");
  256. if(this->checkApproximativeValues(region)){
  257. ++this->numOfRegionsSolvedThroughApproximation;
  258. STORM_LOG_DEBUG("Result '" << region.getCheckResult() <<"' obtained through approximation.");
  259. done=true;
  260. }
  261. }
  262. std::chrono::high_resolution_clock::time_point timeApproximationEnd = std::chrono::high_resolution_clock::now();
  263. std::chrono::high_resolution_clock::time_point timeSamplingStart = std::chrono::high_resolution_clock::now();
  264. if(!done && doSampling){
  265. STORM_LOG_DEBUG("Checking sample points...");
  266. if(this->checkSamplePoints(region)){
  267. ++this->numOfRegionsSolvedThroughSampling;
  268. STORM_LOG_DEBUG("Result '" << region.getCheckResult() <<"' obtained through sampling.");
  269. done=true;
  270. }
  271. }
  272. std::chrono::high_resolution_clock::time_point timeSamplingEnd = std::chrono::high_resolution_clock::now();
  273. std::chrono::high_resolution_clock::time_point timeSmtStart = std::chrono::high_resolution_clock::now();
  274. if(!done && doSmt){
  275. STORM_LOG_DEBUG("Checking with Smt Solving...");
  276. if(this->checkSmt(region)){
  277. ++this->numOfRegionsSolvedThroughSmt;
  278. STORM_LOG_DEBUG("Result '" << region.getCheckResult() <<"' obtained through Smt Solving.");
  279. done=true;
  280. }
  281. }
  282. std::chrono::high_resolution_clock::time_point timeSmtEnd = std::chrono::high_resolution_clock::now();
  283. //some information for statistics...
  284. std::chrono::high_resolution_clock::time_point timeCheckRegionEnd = std::chrono::high_resolution_clock::now();
  285. this->timeCheckRegion += timeCheckRegionEnd-timeCheckRegionStart;
  286. this->timeSampling += timeSamplingEnd - timeSamplingStart;
  287. this->timeApproximation += timeApproximationEnd - timeApproximationStart;
  288. this->timeSmt += timeSmtEnd - timeSmtStart;
  289. switch(region.getCheckResult()){
  290. case RegionCheckResult::EXISTSBOTH:
  291. ++this->numOfRegionsExistsBoth;
  292. break;
  293. case RegionCheckResult::ALLSAT:
  294. ++this->numOfRegionsAllSat;
  295. break;
  296. case RegionCheckResult::ALLVIOLATED:
  297. ++this->numOfRegionsAllViolated;
  298. break;
  299. default:
  300. break;
  301. }
  302. }
  303. template<typename ParametricSparseModelType, typename ConstantType>
  304. bool SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::checkApproximativeValues(ParameterRegion<ParametricType>& region) {
  305. // Decide whether to prove allsat or allviolated.
  306. bool proveAllSat;
  307. switch (region.getCheckResult()){
  308. case RegionCheckResult::UNKNOWN:
  309. switch(this->settings.getApproxMode()){
  310. case storm::settings::modules::RegionSettings::ApproxMode::TESTFIRST:
  311. //Sample a single point to know whether we should try to prove ALLSAT or ALLVIOLATED
  312. checkPoint(region,region.getSomePoint(), false);
  313. proveAllSat= (region.getCheckResult()==RegionCheckResult::EXISTSSAT);
  314. break;
  315. case storm::settings::modules::RegionSettings::ApproxMode::GUESSALLSAT:
  316. proveAllSat=true;
  317. break;
  318. case storm::settings::modules::RegionSettings::ApproxMode::GUESSALLVIOLATED:
  319. proveAllSat=false;
  320. break;
  321. default:
  322. STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "The specified approxmode is not supported");
  323. }
  324. break;
  325. case RegionCheckResult::ALLSAT:
  326. STORM_LOG_WARN("The checkresult of the current region should not be conclusive (ALLSAT)");
  327. //Intentionally no break;
  328. case RegionCheckResult::EXISTSSAT:
  329. proveAllSat=true;
  330. break;
  331. case RegionCheckResult::ALLVIOLATED:
  332. STORM_LOG_WARN("The checkresult of the current region should not be conclusive (ALLViolated)");
  333. //Intentionally no break;
  334. case RegionCheckResult::EXISTSVIOLATED:
  335. proveAllSat=false;
  336. break;
  337. default:
  338. STORM_LOG_WARN("The checkresult of the current region should not be conclusive, i.e. it should be either EXISTSSAT or EXISTSVIOLATED or UNKNOWN in order to apply approximative values");
  339. proveAllSat=true;
  340. }
  341. if(this->checkRegionWithApproximation(region, proveAllSat)){
  342. //approximation was conclusive
  343. if(proveAllSat){
  344. region.setCheckResult(RegionCheckResult::ALLSAT);
  345. } else {
  346. region.setCheckResult(RegionCheckResult::ALLVIOLATED);
  347. }
  348. return true;
  349. }
  350. if(region.getCheckResult()==RegionCheckResult::UNKNOWN){
  351. //In this case, it makes sense to try to prove the contrary statement
  352. proveAllSat=!proveAllSat;
  353. if(this->checkRegionWithApproximation(region, proveAllSat)){
  354. //approximation was conclusive
  355. if(proveAllSat){
  356. region.setCheckResult(RegionCheckResult::ALLSAT);
  357. } else {
  358. region.setCheckResult(RegionCheckResult::ALLVIOLATED);
  359. }
  360. return true;
  361. }
  362. }
  363. //if we reach this point than the result is still inconclusive.
  364. return false;
  365. }
  366. template<typename ParametricSparseModelType, typename ConstantType>
  367. bool SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::checkRegionWithApproximation(ParameterRegion<ParametricType> const& region, bool proveAllSat){
  368. if(this->isResultConstant()){
  369. return (proveAllSat==this->checkFormulaOnSamplingPoint(region.getSomePoint()));
  370. }
  371. bool computeLowerBounds = (this->specifiedFormulaHasLowerBound() && proveAllSat) || (!this->specifiedFormulaHasLowerBound() && !proveAllSat);
  372. bool formulaSatisfied = this->getApproximationModel()->checkFormulaOnRegion(region, computeLowerBounds);
  373. return (proveAllSat==formulaSatisfied);
  374. }
  375. template<typename ParametricSparseModelType, typename ConstantType>
  376. std::shared_ptr<ApproximationModel<ParametricSparseModelType, ConstantType>> const& SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::getApproximationModel() {
  377. if(this->approximationModel==nullptr){
  378. STORM_LOG_WARN("Approximation model requested but it has not been initialized when specifying the formula. Will initialize it now.");
  379. initializeApproximationModel(*this->getSimpleModel(), this->getSimpleFormula());
  380. }
  381. return this->approximationModel;
  382. }
  383. template<typename ParametricSparseModelType, typename ConstantType>
  384. bool SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::checkSamplePoints(ParameterRegion<ParametricType>& region) {
  385. auto samplingPoints = region.getVerticesOfRegion(region.getVariables()); //test the 4 corner points
  386. for (auto const& point : samplingPoints){
  387. if(checkPoint(region, point)){
  388. return true;
  389. }
  390. }
  391. return false;
  392. }
  393. template<typename ParametricSparseModelType, typename ConstantType>
  394. ConstantType SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::getReachabilityValue(std::map<VariableType, CoefficientType> const& point) {
  395. if(this->isResultConstant()){
  396. return this->constantResult.get();
  397. }
  398. return this->getSamplingModel()->computeInitialStateValue(point);
  399. }
  400. template<typename ParametricSparseModelType, typename ConstantType>
  401. bool SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::checkFormulaOnSamplingPoint(std::map<VariableType, CoefficientType> const& point) {
  402. if(this->isResultConstant()){
  403. return this->valueIsInBoundOfFormula(this->constantResult.get());
  404. }
  405. return this->getSamplingModel()->checkFormulaOnSamplingPoint(point);
  406. }
  407. template<typename ParametricSparseModelType, typename ConstantType>
  408. std::shared_ptr<SamplingModel<ParametricSparseModelType, ConstantType>> const& SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::getSamplingModel() {
  409. if(this->samplingModel==nullptr){
  410. STORM_LOG_WARN("Sampling model requested but it has not been initialized when specifying the formula. Will initialize it now.");
  411. initializeSamplingModel(*this->getSimpleModel(), this->getSimpleFormula());
  412. }
  413. return this->samplingModel;
  414. }
  415. template<typename ParametricSparseModelType, typename ConstantType>
  416. bool SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::valueIsInBoundOfFormula(ConstantType const& value){
  417. STORM_LOG_THROW(this->getSpecifiedFormula()!=nullptr, storm::exceptions::InvalidStateException, "Tried to compare a value to the bound of a formula, but no formula specified.");
  418. switch (this->getSpecifiedFormula()->getComparisonType()) {
  419. case storm::logic::ComparisonType::Greater:
  420. return (value > this->getSpecifiedFormulaBound());
  421. case storm::logic::ComparisonType::GreaterEqual:
  422. return (value >= this->getSpecifiedFormulaBound());
  423. case storm::logic::ComparisonType::Less:
  424. return (value < this->getSpecifiedFormulaBound());
  425. case storm::logic::ComparisonType::LessEqual:
  426. return (value <= this->getSpecifiedFormulaBound());
  427. default:
  428. STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "the comparison relation of the formula is not supported");
  429. }
  430. }
  431. template<typename ParametricSparseModelType, typename ConstantType>
  432. bool SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::valueIsInBoundOfFormula(CoefficientType const& value){
  433. return valueIsInBoundOfFormula(storm::utility::region::convertNumber<ConstantType>(value));
  434. }
  435. template<typename ParametricSparseModelType, typename ConstantType>
  436. void SparseRegionModelChecker<ParametricSparseModelType, ConstantType>::printStatisticsToStream(std::ostream& outstream) {
  437. STORM_LOG_DEBUG("Printing statistics");
  438. if(this->getSpecifiedFormula()==nullptr){
  439. outstream << "Region Model Checker Statistics Error: No formula specified." << std::endl;
  440. return;
  441. }
  442. std::chrono::milliseconds timeSpecifyFormulaInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(this->timeSpecifyFormula);
  443. std::chrono::milliseconds timePreprocessingInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(this->timePreprocessing);
  444. std::chrono::milliseconds timeInitSamplingModelInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(this->timeInitSamplingModel);
  445. std::chrono::milliseconds timeInitApproxModelInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(this->timeInitApproxModel);
  446. std::chrono::milliseconds timeComputeReachabilityFunctionInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(this->timeComputeReachabilityFunction);
  447. std::chrono::milliseconds timeCheckRegionInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(this->timeCheckRegion);
  448. std::chrono::milliseconds timeSammplingInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(this->timeSampling);
  449. std::chrono::milliseconds timeApproximationInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(this->timeApproximation);
  450. std::chrono::milliseconds timeSmtInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(this->timeSmt);
  451. std::chrono::high_resolution_clock::duration timeOverall = timeSpecifyFormula + timeCheckRegion; // + ...
  452. std::chrono::milliseconds timeOverallInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(timeOverall);
  453. uint_fast64_t numOfSolvedRegions= this->numOfRegionsExistsBoth + this->numOfRegionsAllSat + this->numOfRegionsAllViolated;
  454. outstream << std::endl << "Region Model Checker Statistics:" << std::endl;
  455. outstream << "-----------------------------------------------" << std::endl;
  456. outstream << "Model: " << this->model->getNumberOfStates() << " states, " << this->model->getNumberOfTransitions() << " transitions." << std::endl;
  457. outstream << "Formula: " << *this->getSpecifiedFormula() << std::endl;
  458. if(this->isResultConstant()){
  459. outstream << "The requested value is constant (i.e. independent of any parameters)" << std::endl;
  460. }
  461. else{
  462. outstream << "Simple model: " << this->getSimpleModel()->getNumberOfStates() << " states, " << this->getSimpleModel()->getNumberOfTransitions() << " transitions" << std::endl;
  463. outstream << "Simple formula: " << *this->getSimpleFormula() << std::endl;
  464. }
  465. outstream << "Approximation is " << (this->isApproximationApplicable ? "" : "not ") << "applicable" << std::endl;
  466. outstream << "Number of checked regions: " << this->numOfCheckedRegions << std::endl;
  467. if(this->numOfCheckedRegions>0){
  468. outstream << " Number of solved regions: " << numOfSolvedRegions << "(" << numOfSolvedRegions*100/this->numOfCheckedRegions << "%)" << std::endl;
  469. outstream << " AllSat: " << this->numOfRegionsAllSat << "(" << this->numOfRegionsAllSat*100/this->numOfCheckedRegions << "%)" << std::endl;
  470. outstream << " AllViolated: " << this->numOfRegionsAllViolated << "(" << this->numOfRegionsAllViolated*100/this->numOfCheckedRegions << "%)" << std::endl;
  471. outstream << " ExistsBoth: " << this->numOfRegionsExistsBoth << "(" << this->numOfRegionsExistsBoth*100/this->numOfCheckedRegions << "%)" << std::endl;
  472. outstream << " Unsolved: " << this->numOfCheckedRegions - numOfSolvedRegions << "(" << (this->numOfCheckedRegions - numOfSolvedRegions)*100/this->numOfCheckedRegions << "%)" << std::endl;
  473. outstream << " -- Note: %-numbers are relative to the NUMBER of regions, not the size of their area --" << std::endl;
  474. outstream << " " << this->numOfRegionsSolvedThroughApproximation << " regions solved through Approximation" << std::endl;
  475. outstream << " " << this->numOfRegionsSolvedThroughSampling << " regions solved through Sampling" << std::endl;
  476. outstream << " " << this->numOfRegionsSolvedThroughSmt << " regions solved through Smt" << std::endl;
  477. outstream << std::endl;
  478. }
  479. outstream << "Running times:" << std::endl;
  480. outstream << " " << timeOverallInMilliseconds.count() << "ms overall (excluding model parsing, bisimulation (if applied))" << std::endl;
  481. outstream << " " << timeSpecifyFormulaInMilliseconds.count() << "ms Initialization for the specified formula, including... " << std::endl;
  482. outstream << " " << timePreprocessingInMilliseconds.count() << "ms for Preprocessing (mainly: state elimination of const transitions), including" << std::endl;
  483. outstream << " " << timeComputeReachabilityFunctionInMilliseconds.count() << "ms to compute the reachability function" << std::endl;
  484. outstream << " " << timeInitApproxModelInMilliseconds.count() << "ms to initialize the Approximation Model" << std::endl;
  485. outstream << " " << timeInitSamplingModelInMilliseconds.count() << "ms to initialize the Sampling Model" << std::endl;
  486. outstream << " " << timeCheckRegionInMilliseconds.count() << "ms Region Check including... " << std::endl;
  487. outstream << " " << timeApproximationInMilliseconds.count() << "ms Approximation" << std::endl;
  488. outstream << " " << timeSammplingInMilliseconds.count() << "ms Sampling " << std::endl;
  489. outstream << " " << timeSmtInMilliseconds.count() << "ms Smt solving" << std::endl;
  490. outstream << "-----------------------------------------------" << std::endl;
  491. outstream << "CSV format;" << timeOverallInMilliseconds.count() << ";" << this->numOfRegionsAllSat << ";" << this->numOfRegionsAllViolated << ";" << this->numOfRegionsExistsBoth << ";" << (this->numOfCheckedRegions-numOfSolvedRegions) << std::endl;
  492. }
  493. //note: for other template instantiations, add rules for the typedefs of VariableType and CoefficientType in utility/regions.h
  494. #ifdef STORM_HAVE_CARL
  495. template class SparseRegionModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>;
  496. template class SparseRegionModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>;
  497. #endif
  498. } // namespace region
  499. } //namespace modelchecker
  500. } //namespace storm