#include #include #include "storm-pars/modelchecker/region/RegionModelChecker.h" #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/utility/vector.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Mdp.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/exceptions/NotImplementedException.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/InvalidArgumentException.h" namespace storm { namespace modelchecker { template RegionModelChecker::RegionModelChecker() { // Intentionally left empty } template std::unique_ptr> RegionModelChecker::analyzeRegions(Environment const& env, std::vector> const& regions, std::vector const& hypotheses, bool sampleVerticesOfRegion) { STORM_LOG_THROW(regions.size() == hypotheses.size(), storm::exceptions::InvalidArgumentException, "The number of regions and the number of hypotheses do not match"); std::vector, storm::modelchecker::RegionResult>> result; auto hypothesisIt = hypotheses.begin(); for (auto const& region : regions) { storm::modelchecker::RegionResult regionRes = analyzeRegion(env, region, *hypothesisIt, storm::modelchecker::RegionResult::Unknown, sampleVerticesOfRegion); result.emplace_back(region, regionRes); ++hypothesisIt; } return std::make_unique>(std::move(result)); } template ParametricType RegionModelChecker::getBoundAtInitState(Environment const& env, storm::storage::ParameterRegion const& region, storm::solver::OptimizationDirection const& dirForParameters) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "The selected region model checker does not support this functionality."); return storm::utility::zero(); } template std::unique_ptr> RegionModelChecker::performRegionRefinement(Environment const& env, storm::storage::ParameterRegion const& region, boost::optional const& coverageThreshold, boost::optional depthThreshold, RegionResultHypothesis const& hypothesis) { STORM_LOG_INFO("Applying refinement on region: " << region.toString(true) << " ."); auto thresholdAsCoefficient = coverageThreshold ? storm::utility::convertNumber(coverageThreshold.get()) : storm::utility::zero(); auto areaOfParameterSpace = region.area(); auto fractionOfUndiscoveredArea = storm::utility::one(); auto fractionOfAllSatArea = storm::utility::zero(); auto fractionOfAllViolatedArea = storm::utility::zero(); // The resulting (sub-)regions std::vector, RegionResult>> result; // FIFO queues storing the data for the regions that we still need to process. std::queue, RegionResult>> unprocessedRegions; std::queue refinementDepths; unprocessedRegions.emplace(region, RegionResult::Unknown); refinementDepths.push(0); uint_fast64_t numOfAnalyzedRegions = 0; CoefficientType displayedProgress = storm::utility::zero(); if (storm::settings::getModule().isShowStatisticsSet()) { STORM_PRINT_AND_LOG("Progress (solved fraction) :" << std::endl << "0% ["); while (displayedProgress < storm::utility::one() - thresholdAsCoefficient) { STORM_PRINT_AND_LOG(" "); displayedProgress += storm::utility::convertNumber(0.01); } while (displayedProgress < storm::utility::one()) { STORM_PRINT_AND_LOG("-"); displayedProgress += storm::utility::convertNumber(0.01); } STORM_PRINT_AND_LOG("] 100%" << std::endl << " ["); displayedProgress = storm::utility::zero(); } while (fractionOfUndiscoveredArea > thresholdAsCoefficient && !unprocessedRegions.empty()) { assert(unprocessedRegions.size() == refinementDepths.size()); uint64_t currentDepth = refinementDepths.front(); STORM_LOG_INFO("Analyzing region #" << numOfAnalyzedRegions << " (Refinement depth " << currentDepth << "; " << storm::utility::convertNumber(fractionOfUndiscoveredArea) * 100 << "% still unknown)"); auto& currentRegion = unprocessedRegions.front().first; auto& res = unprocessedRegions.front().second; res = analyzeRegion(env, currentRegion, hypothesis, res, false); switch (res) { case RegionResult::AllSat: fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace; fractionOfAllSatArea += currentRegion.area() / areaOfParameterSpace; result.push_back(std::move(unprocessedRegions.front())); break; case RegionResult::AllViolated: fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace; fractionOfAllViolatedArea += currentRegion.area() / areaOfParameterSpace; result.push_back(std::move(unprocessedRegions.front())); break; default: // Split the region as long as the desired refinement depth is not reached. if (!depthThreshold || currentDepth < depthThreshold.get()) { std::vector> newRegions; currentRegion.split(currentRegion.getCenterPoint(), newRegions); RegionResult initResForNewRegions = (res == RegionResult::CenterSat) ? RegionResult::ExistsSat : ((res == RegionResult::CenterViolated) ? RegionResult::ExistsViolated : RegionResult::Unknown); for (auto& newRegion : newRegions) { unprocessedRegions.emplace(std::move(newRegion), initResForNewRegions); refinementDepths.push(currentDepth + 1); } } else { // If the region is not further refined, it is still added to the result result.push_back(std::move(unprocessedRegions.front())); } break; } ++numOfAnalyzedRegions; unprocessedRegions.pop(); refinementDepths.pop(); if (storm::settings::getModule().isShowStatisticsSet()) { while (displayedProgress < storm::utility::one() - fractionOfUndiscoveredArea) { STORM_PRINT_AND_LOG("#"); displayedProgress += storm::utility::convertNumber(0.01); } } } // Add the still unprocessed regions to the result while (!unprocessedRegions.empty()) { result.push_back(std::move(unprocessedRegions.front())); unprocessedRegions.pop(); } if (storm::settings::getModule().isShowStatisticsSet()) { while (displayedProgress < storm::utility::one()) { STORM_PRINT_AND_LOG("-"); displayedProgress += storm::utility::convertNumber(0.01); } STORM_PRINT_AND_LOG("]" << std::endl); STORM_PRINT_AND_LOG("Region Refinement Statistics:" << std::endl); STORM_PRINT_AND_LOG(" Analyzed a total of " << numOfAnalyzedRegions << " regions." << std::endl); } auto regionCopyForResult = region; return std::make_unique>(std::move(result), std::move(regionCopyForResult)); } template std::pair::Valuation> RegionModelChecker::computeExtremalValue(Environment const& env, storm::storage::ParameterRegion const& region, storm::solver::OptimizationDirection const& dir, ParametricType const& precision) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Computing extremal values is not supported for this region model checker."); return std::pair::Valuation>(); } template bool RegionModelChecker::isRegionSplitEstimateSupported() const { return false; } template std::map::VariableType, double> RegionModelChecker::getRegionSplitEstimate() const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Region split estimation is not supported by this region model checker."); return std::map::VariableType, double>(); } #ifdef STORM_HAVE_CARL template class RegionModelChecker; #endif } //namespace modelchecker } //namespace storm