#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h" #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/logic/FragmentSpecification.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/NotSupportedException.h" namespace storm { namespace modelchecker { template SparseParameterLiftingModelChecker::SparseParameterLiftingModelChecker() { //Intentionally left empty } template void SparseParameterLiftingModelChecker::specifyFormula(storm::modelchecker::CheckTask const& checkTask) { currentFormula = checkTask.getFormula().asSharedPointer(); currentCheckTask = std::make_unique>(checkTask.substituteFormula(*currentFormula).template convertValueType()); if(currentCheckTask->getFormula().isProbabilityOperatorFormula()) { auto const& probOpFormula = currentCheckTask->getFormula().asProbabilityOperatorFormula(); if(probOpFormula.getSubformula().isBoundedUntilFormula()) { specifyBoundedUntilFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asBoundedUntilFormula())); } else if(probOpFormula.getSubformula().isUntilFormula()) { specifyUntilFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asUntilFormula())); } else if (probOpFormula.getSubformula().isEventuallyFormula()) { specifyReachabilityProbabilityFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asEventuallyFormula())); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); } } else if (currentCheckTask->getFormula().isRewardOperatorFormula()) { auto const& rewOpFormula = currentCheckTask->getFormula().asRewardOperatorFormula(); if(rewOpFormula.getSubformula().isEventuallyFormula()) { specifyReachabilityRewardFormula(currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asEventuallyFormula())); } else if (rewOpFormula.getSubformula().isCumulativeRewardFormula()) { specifyCumulativeRewardFormula(currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asCumulativeRewardFormula())); } } } template RegionResult SparseParameterLiftingModelChecker::analyzeRegion(storm::storage::ParameterRegion const& region, RegionResultHypothesis const& hypothesis, RegionResult const& initialResult, bool sampleVerticesOfRegion) { STORM_LOG_THROW(this->currentCheckTask->isOnlyInitialStatesRelevantSet(), storm::exceptions::NotSupportedException, "Analyzing regions with parameter lifting requires a property where only the value in the initial states is relevant."); STORM_LOG_THROW(this->currentCheckTask->isBoundSet(), storm::exceptions::NotSupportedException, "Analyzing regions with parameter lifting requires a bounded property."); STORM_LOG_THROW(this->parametricModel->getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::NotSupportedException, "Analyzing regions with parameter lifting requires a model with a single initial state."); RegionResult result = initialResult; // Check if we need to check the formula on one point to decide whether to show AllSat or AllViolated if (hypothesis == RegionResultHypothesis::Unknown && result == RegionResult::Unknown) { result = getInstantiationChecker().check(region.getCenterPoint())->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()] ? RegionResult::CenterSat : RegionResult::CenterViolated; } // try to prove AllSat or AllViolated, depending on the hypothesis or the current result if (hypothesis == RegionResultHypothesis::AllSat || result == RegionResult::ExistsSat || result == RegionResult::CenterSat) { // show AllSat: storm::solver::OptimizationDirection parameterOptimizationDirection = isLowerBound(this->currentCheckTask->getBound().comparisonType) ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize; if (this->check(region, parameterOptimizationDirection)->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()]) { result = RegionResult::AllSat; } else if (sampleVerticesOfRegion) { result = sampleVertices(region, result); } } else if (hypothesis == RegionResultHypothesis::AllViolated || result == RegionResult::ExistsViolated || result == RegionResult::CenterViolated) { // show AllViolated: storm::solver::OptimizationDirection parameterOptimizationDirection = isLowerBound(this->currentCheckTask->getBound().comparisonType) ? storm::solver::OptimizationDirection::Maximize : storm::solver::OptimizationDirection::Minimize; if (!this->check(region, parameterOptimizationDirection)->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()]) { result = RegionResult::AllViolated; } else if (sampleVerticesOfRegion) { result = sampleVertices(region, result); } } else { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "When analyzing a region, an invalid initial result was given: " << initialResult); } return result; } template RegionResult SparseParameterLiftingModelChecker::sampleVertices(storm::storage::ParameterRegion const& region, RegionResult const& initialResult) { RegionResult result = initialResult; if (result == RegionResult::AllSat || result == RegionResult::AllViolated) { return result; } bool hasSatPoint = result == RegionResult::ExistsSat || result == RegionResult::CenterSat; bool hasViolatedPoint = result == RegionResult::ExistsViolated || result == RegionResult::CenterViolated; // Check if there is a point in the region for which the property is satisfied auto vertices = region.getVerticesOfRegion(region.getVariables()); auto vertexIt = vertices.begin(); while (vertexIt != vertices.end() && !(hasSatPoint && hasViolatedPoint)) { if (getInstantiationChecker().check(*vertexIt)->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()]) { hasSatPoint = true; } else { hasViolatedPoint = true; } ++vertexIt; } if (hasSatPoint) { if (hasViolatedPoint) { result = RegionResult::ExistsBoth; } else if (result != RegionResult::CenterSat) { result = RegionResult::ExistsSat; } } else if (hasViolatedPoint && result != RegionResult::CenterViolated) { result = RegionResult::ExistsViolated; } return result; } template std::unique_ptr SparseParameterLiftingModelChecker::check(storm::storage::ParameterRegion const& region, storm::solver::OptimizationDirection const& dirForParameters) { auto quantitativeResult = computeQuantitativeValues(region, dirForParameters); if(currentCheckTask->getFormula().hasQuantitativeResult()) { return quantitativeResult; } else { return quantitativeResult->template asExplicitQuantitativeCheckResult().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs()); } } template SparseModelType const& SparseParameterLiftingModelChecker::getConsideredParametricModel() const { return *parametricModel; } template CheckTask const& SparseParameterLiftingModelChecker::getCurrentCheckTask() const { return *currentCheckTask; } template void SparseParameterLiftingModelChecker::specifyBoundedUntilFormula(CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); } template void SparseParameterLiftingModelChecker::specifyUntilFormula(CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); } template void SparseParameterLiftingModelChecker::specifyReachabilityProbabilityFormula(CheckTask const& checkTask) { // transform to until formula auto untilFormula = std::make_shared(storm::logic::Formula::getTrueFormula(), checkTask.getFormula().getSubformula().asSharedPointer()); specifyUntilFormula(currentCheckTask->substituteFormula(*untilFormula)); } template void SparseParameterLiftingModelChecker::specifyReachabilityRewardFormula(CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); } template void SparseParameterLiftingModelChecker::specifyCumulativeRewardFormula(CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); } template class SparseParameterLiftingModelChecker, double>; template class SparseParameterLiftingModelChecker, double>; template class SparseParameterLiftingModelChecker, storm::RationalNumber>; template class SparseParameterLiftingModelChecker, storm::RationalNumber>; } }