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.
179 lines
11 KiB
179 lines
11 KiB
#include <sstream>
|
|
#include <queue>
|
|
|
|
#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 <typename ParametricType>
|
|
RegionModelChecker<ParametricType>::RegionModelChecker() {
|
|
// Intentionally left empty
|
|
}
|
|
|
|
template <typename ParametricType>
|
|
std::unique_ptr<storm::modelchecker::RegionCheckResult<ParametricType>> RegionModelChecker<ParametricType>::analyzeRegions(Environment const& env, std::vector<storm::storage::ParameterRegion<ParametricType>> const& regions, std::vector<RegionResultHypothesis> 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<std::pair<storm::storage::ParameterRegion<ParametricType>, 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<storm::modelchecker::RegionCheckResult<ParametricType>>(std::move(result));
|
|
}
|
|
|
|
template <typename ParametricType>
|
|
ParametricType RegionModelChecker<ParametricType>::getBoundAtInitState(Environment const& env, storm::storage::ParameterRegion<ParametricType> 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<ParametricType>();
|
|
}
|
|
|
|
template <typename ParametricType>
|
|
std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ParametricType>> RegionModelChecker<ParametricType>::performRegionRefinement(Environment const& env, storm::storage::ParameterRegion<ParametricType> const& region, boost::optional<ParametricType> const& coverageThreshold, boost::optional<uint64_t> depthThreshold, RegionResultHypothesis const& hypothesis) {
|
|
STORM_LOG_INFO("Applying refinement on region: " << region.toString(true) << " .");
|
|
|
|
auto thresholdAsCoefficient = coverageThreshold ? storm::utility::convertNumber<CoefficientType>(coverageThreshold.get()) : storm::utility::zero<CoefficientType>();
|
|
auto areaOfParameterSpace = region.area();
|
|
auto fractionOfUndiscoveredArea = storm::utility::one<CoefficientType>();
|
|
auto fractionOfAllSatArea = storm::utility::zero<CoefficientType>();
|
|
auto fractionOfAllViolatedArea = storm::utility::zero<CoefficientType>();
|
|
|
|
// The resulting (sub-)regions
|
|
std::vector<std::pair<storm::storage::ParameterRegion<ParametricType>, RegionResult>> result;
|
|
|
|
// FIFO queues storing the data for the regions that we still need to process.
|
|
std::queue<std::pair<storm::storage::ParameterRegion<ParametricType>, RegionResult>> unprocessedRegions;
|
|
std::queue<uint64_t> refinementDepths;
|
|
unprocessedRegions.emplace(region, RegionResult::Unknown);
|
|
refinementDepths.push(0);
|
|
|
|
uint_fast64_t numOfAnalyzedRegions = 0;
|
|
CoefficientType displayedProgress = storm::utility::zero<CoefficientType>();
|
|
if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
|
|
STORM_PRINT_AND_LOG("Progress (solved fraction) :" << std::endl << "0% [");
|
|
while (displayedProgress < storm::utility::one<CoefficientType>() - thresholdAsCoefficient) {
|
|
STORM_PRINT_AND_LOG(" ");
|
|
displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
|
|
}
|
|
while (displayedProgress < storm::utility::one<CoefficientType>()) {
|
|
STORM_PRINT_AND_LOG("-");
|
|
displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
|
|
}
|
|
STORM_PRINT_AND_LOG("] 100%" << std::endl << " [");
|
|
displayedProgress = storm::utility::zero<CoefficientType>();
|
|
}
|
|
|
|
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<double>(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<storm::storage::ParameterRegion<ParametricType>> 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<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
|
|
while (displayedProgress < storm::utility::one<CoefficientType>() - fractionOfUndiscoveredArea) {
|
|
STORM_PRINT_AND_LOG("#");
|
|
displayedProgress += storm::utility::convertNumber<CoefficientType>(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<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
|
|
while (displayedProgress < storm::utility::one<CoefficientType>()) {
|
|
STORM_PRINT_AND_LOG("-");
|
|
displayedProgress += storm::utility::convertNumber<CoefficientType>(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<storm::modelchecker::RegionRefinementCheckResult<ParametricType>>(std::move(result), std::move(regionCopyForResult));
|
|
}
|
|
|
|
template <typename ParametricType>
|
|
std::pair<ParametricType, typename storm::storage::ParameterRegion<ParametricType>::Valuation> RegionModelChecker<ParametricType>::computeExtremalValue(Environment const& env, storm::storage::ParameterRegion<ParametricType> 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<ParametricType, typename storm::storage::ParameterRegion<ParametricType>::Valuation>();
|
|
}
|
|
|
|
|
|
template <typename ParametricType>
|
|
bool RegionModelChecker<ParametricType>::isRegionSplitEstimateSupported() const {
|
|
return false;
|
|
}
|
|
|
|
template <typename ParametricType>
|
|
std::map<typename RegionModelChecker<ParametricType>::VariableType, double> RegionModelChecker<ParametricType>::getRegionSplitEstimate() const {
|
|
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Region split estimation is not supported by this region model checker.");
|
|
return std::map<typename RegionModelChecker<ParametricType>::VariableType, double>();
|
|
}
|
|
|
|
|
|
#ifdef STORM_HAVE_CARL
|
|
template class RegionModelChecker<storm::RationalFunction>;
|
|
#endif
|
|
} //namespace modelchecker
|
|
} //namespace storm
|
|
|