Storm 1.13.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseParameterLiftingModelChecker.cpp
Go to the documentation of this file.
2
18
19namespace storm {
20namespace modelchecker {
21
22template<typename SparseModelType, typename ConstantType>
26
27template<typename SparseModelType, typename ConstantType>
30 currentFormula = checkTask.getFormula().asSharedPointer();
31 currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ConstantType>>(
32 checkTask.substituteFormula(*currentFormula).template convertValueType<ConstantType>());
33
34 if (currentCheckTask->getFormula().isProbabilityOperatorFormula()) {
35 auto const& probOpFormula = currentCheckTask->getFormula().asProbabilityOperatorFormula();
36 if (probOpFormula.getSubformula().isBoundedUntilFormula()) {
37 specifyBoundedUntilFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asBoundedUntilFormula()));
38 } else if (probOpFormula.getSubformula().isUntilFormula()) {
39 specifyUntilFormula(env, currentCheckTask->substituteFormula(probOpFormula.getSubformula().asUntilFormula()));
40 } else if (probOpFormula.getSubformula().isEventuallyFormula()) {
41 specifyReachabilityProbabilityFormula(env, currentCheckTask->substituteFormula(probOpFormula.getSubformula().asEventuallyFormula()));
42 } else {
43 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
44 }
45 } else if (currentCheckTask->getFormula().isRewardOperatorFormula()) {
46 auto const& rewOpFormula = currentCheckTask->getFormula().asRewardOperatorFormula();
47 if (rewOpFormula.getSubformula().isEventuallyFormula()) {
48 specifyReachabilityRewardFormula(env, currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asEventuallyFormula()));
49 } else if (rewOpFormula.getSubformula().isCumulativeRewardFormula()) {
50 specifyCumulativeRewardFormula(currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asCumulativeRewardFormula()));
51 }
52 }
53}
54
55template<typename SparseModelType, typename ConstantType>
57 return this->parametricModel->getInitialStates().getNumberOfSetBits() == 1;
58}
59
60template<typename SparseModelType, typename ConstantType>
62 STORM_LOG_ASSERT(hasUniqueInitialState(), "Model does not have a unique initial state.");
63 return *this->parametricModel->getInitialStates().begin();
64}
65
66template<typename RegionType>
68 std::map<typename RegionType::VariableType, storm::analysis::MonotonicityKind> const& monotonicityResult,
70 typename RegionType::Valuation result;
71 for (auto const& [var, mon] : monotonicityResult) {
73 result.emplace(var, region.getLowerBoundary(var));
75 result.emplace(var, storm::solver::maximize(dir) ? region.getUpperBoundary(var) : region.getLowerBoundary(var));
77 result.emplace(var, storm::solver::minimize(dir) ? region.getUpperBoundary(var) : region.getLowerBoundary(var));
78 }
79 }
80 return result;
81}
82
83template<typename SparseModelType, typename ConstantType>
85 RegionResultHypothesis const& hypothesis,
86 bool sampleVerticesOfRegion) {
87 STORM_LOG_THROW(this->currentCheckTask->isOnlyInitialStatesRelevantSet(), storm::exceptions::NotSupportedException,
88 "Analyzing regions with parameter lifting requires a property where only the value in the initial states is relevant.");
89 STORM_LOG_THROW(this->currentCheckTask->isBoundSet(), storm::exceptions::NotSupportedException,
90 "Analyzing regions with parameter lifting requires a bounded property.");
91 STORM_LOG_THROW(hasUniqueInitialState(), storm::exceptions::NotSupportedException,
92 "Analyzing regions with parameter lifting requires a model with a single initial state.");
93
94 RegionResult result = region.result;
95 if (result == RegionResult::AllSat || result == RegionResult::AllViolated || result == RegionResult::ExistsBoth) {
96 return result; // Result is already known, nothing to do.
97 }
98
99 // Check if we need to check the formula on one point to decide whether to show AllSat or AllViolated
100 if (hypothesis == RegionResultHypothesis::Unknown &&
102 auto const center = region.region.getCenterPoint();
103 if (getInstantiationChecker(false).isWellDefined(center)) {
104 result = getInstantiationChecker(false).check(env, center)->template asExplicitQualitativeCheckResult<ConstantType>()[getUniqueInitialState()]
107 } else {
108 auto const lowerCorner = region.region.getLowerBoundaries();
109 if (getInstantiationChecker(false).isWellDefined(lowerCorner)) {
110 result =
111 getInstantiationChecker(false).check(env, lowerCorner)->template asExplicitQualitativeCheckResult<ConstantType>()[getUniqueInitialState()]
114 } else {
116 }
117 }
118 }
119
120 bool const existsSat = (hypothesis == RegionResultHypothesis::AllSat || result == RegionResult::ExistsSat || result == RegionResult::CenterSat);
121 bool const existsIllDefined = (result == RegionResult::ExistsIllDefined || result == RegionResult::CenterIllDefined);
122 {
123 [[maybe_unused]] bool const existsViolated =
125 STORM_LOG_ASSERT(existsSat + existsViolated + existsIllDefined == 1,
126 "Invalid state of region analysis."); // At this point, exactly one of the three cases must be true
127 }
128 auto const dirForSat =
129 isLowerBound(this->currentCheckTask->getBound().comparisonType) ? storm::OptimizationDirection::Minimize : storm::OptimizationDirection::Maximize;
130
131 std::vector<storm::OptimizationDirection> dirsToCheck;
132 if (existsSat) {
133 dirsToCheck = {dirForSat};
134 } else if (existsIllDefined) {
135 dirsToCheck = {dirForSat, storm::solver::invert(dirForSat)};
136 } else {
137 dirsToCheck = {storm::solver::invert(dirForSat)};
138 }
139
140 for (auto const& dirToCheck : dirsToCheck) {
141 // Try solving through global monotonicity
142 if (auto globalMonotonicity = region.monotonicityAnnotation.getGlobalMonotonicityResult();
143 globalMonotonicity.has_value() && globalMonotonicity->isDone() && globalMonotonicity->isAllMonotonicity()) {
144 auto const valuation = getOptimalValuationForMonotonicity(region.region, globalMonotonicity->getMonotonicityResult(), dirToCheck);
145 STORM_LOG_ASSERT(valuation.size() == region.region.getVariables().size(), "Not all parameters seem to be monotonic.");
146 auto& checker = existsSat ? getInstantiationCheckerSAT(false) : getInstantiationCheckerVIO(false);
147 bool const monCheckResult = checker.check(env, valuation)->template asExplicitQualitativeCheckResult<ConstantType>()[getUniqueInitialState()];
148 if (existsSat == monCheckResult) {
149 result = existsSat ? RegionResult::AllSat : RegionResult::AllViolated;
150 STORM_LOG_INFO("Region " << region.region << " is " << result << ", discovered with instantiation checker on " << valuation
151 << " and help of monotonicity\n");
152 region.resultKnownThroughMonotonicity = true;
153 } else if (result == RegionResult::ExistsSat || result == RegionResult::CenterSat || result == RegionResult::ExistsViolated ||
155 // We found a satisfying and a violating point
157 } else {
159 "This case should only be reached if the initial region result is unknown, but it is " << result << ".");
160 result = monCheckResult ? RegionResult::ExistsSat : RegionResult::ExistsViolated;
161 if (sampleVerticesOfRegion) {
162 result = sampleVertices(env, region.region, result);
163 }
164 }
165 } else {
166 // Try to prove AllSat or AllViolated through parameterLifting
167 auto const checkResult = this->check(env, region, dirToCheck);
168 if (checkResult) {
169 bool const value = checkResult->template asExplicitQualitativeCheckResult<ConstantType>()[getUniqueInitialState()];
170 if ((dirToCheck == dirForSat) == value) {
171 result = (dirToCheck == dirForSat) ? RegionResult::AllSat : RegionResult::AllViolated;
172 } else if (sampleVerticesOfRegion) {
173 result = sampleVertices(env, region.region, result);
174 }
175 } else {
177 }
178 }
179 }
180 return result;
181}
182
183template<typename SparseModelType, typename ConstantType>
186 RegionResult const& initialResult) {
187 RegionResult result = initialResult;
188
189 if (result == RegionResult::AllSat || result == RegionResult::AllViolated) {
190 return result;
191 }
192
193 bool hasSatPoint = result == RegionResult::ExistsSat || result == RegionResult::CenterSat;
194 bool hasViolatedPoint = result == RegionResult::ExistsViolated || result == RegionResult::CenterViolated;
195
196 // Check if there is a point in the region for which the property is satisfied
197 auto vertices = region.getVerticesOfRegion(region.getVariables());
198 auto vertexIt = vertices.begin();
199 while (vertexIt != vertices.end() && !(hasSatPoint && hasViolatedPoint)) {
200 if (getInstantiationChecker(false).check(env, *vertexIt)->template asExplicitQualitativeCheckResult<ConstantType>()[getUniqueInitialState()]) {
201 hasSatPoint = true;
202 } else {
203 hasViolatedPoint = true;
204 }
205 ++vertexIt;
206 }
207
208 if (hasSatPoint) {
209 if (hasViolatedPoint) {
211 } else if (result != RegionResult::CenterSat) {
213 }
214 } else if (hasViolatedPoint && result != RegionResult::CenterViolated) {
216 }
217
218 return result;
219}
220
221template<typename SparseModelType, typename ConstantType>
224 auto quantitativeResult = computeQuantitativeValues(env, region, dirForParameters);
225 if (quantitativeResult.size() == 0) {
226 return nullptr;
227 }
228 auto quantitativeCheckResult = std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(std::move(quantitativeResult));
229 if (currentCheckTask->getFormula().hasQuantitativeResult()) {
230 return quantitativeCheckResult;
231 } else {
232 return quantitativeCheckResult->compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(),
233 this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
234 }
235}
236
237template<typename SparseModelType, typename ConstantType>
238std::unique_ptr<QuantitativeCheckResult<ConstantType>> SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::getBound(
240 STORM_LOG_WARN_COND(this->currentCheckTask->getFormula().hasQuantitativeResult(), "Computing quantitative bounds for a qualitative formula...");
241 return std::make_unique<ExplicitQuantitativeCheckResult<ConstantType>>(computeQuantitativeValues(env, region, dirForParameters));
242}
243
244template<typename SparseModelType, typename ConstantType>
247 storm::solver::OptimizationDirection const& dirForParameters) {
248 STORM_LOG_THROW(hasUniqueInitialState(), storm::exceptions::NotSupportedException,
249 "Getting a bound at the initial state requires a model with a single initial state.");
250 auto result = computeQuantitativeValues(env, region, dirForParameters).at(getUniqueInitialState());
252}
253
254template<typename SparseModelType, typename ConstantType>
259
260template<typename SparseModelType, typename ConstantType>
265
266template<typename SparseModelType, typename ConstantType>
270
271template<typename SparseModelType, typename ConstantType>
275
276template<typename SparseModelType, typename ConstantType>
279 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
280}
281
282template<typename SparseModelType, typename ConstantType>
285 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
286}
287
288template<typename SparseModelType, typename ConstantType>
291 // transform to until formula
292 auto untilFormula =
293 std::make_shared<storm::logic::UntilFormula const>(storm::logic::Formula::getTrueFormula(), checkTask.getFormula().getSubformula().asSharedPointer());
294 specifyUntilFormula(env, currentCheckTask->substituteFormula(*untilFormula));
295}
296
297template<typename SparseModelType, typename ConstantType>
300 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
301}
302
303template<typename SparseModelType, typename ConstantType>
306 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
307}
308
309template<typename SparseModelType, typename ConstantType>
310std::pair<typename SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::CoefficientType,
313 OptimizationDirection const& dirForParameters) {
314 // Take region boundaries for parameters that are known to be monotonic or where there is hope for monotonicity
315 auto point = getOptimalValuationForMonotonicity(region.region, this->monotonicityBackend->getOptimisticMonotonicityApproximation(region), dirForParameters);
316 // Fill in missing parameters with the center point
317 for (auto const& var : region.region.getVariables()) {
318 point.emplace(var, region.region.getCenter(var)); // does not overwrite existing values
319 }
320 auto value = getInstantiationChecker(true).check(env, point)->template asExplicitQuantitativeCheckResult<ConstantType>()[getUniqueInitialState()];
321
322 return std::make_pair(storm::utility::convertNumber<CoefficientType>(value), std::move(point));
323}
324
325template<typename SparseModelType, typename ConstantType>
328 std::vector<ConstantType> const& newValues) {
329 if (hasUniqueInitialState()) {
330 // Catch the infinity case since conversion might fail otherwise
331 auto const& newValue = newValues.at(getUniqueInitialState());
332 CoefficientType convertedValue =
334 region.updateValueBound(convertedValue, dir);
335 }
336}
337
342} // namespace modelchecker
343} // namespace storm
static std::shared_ptr< Formula const > getTrueFormula()
Definition Formula.cpp:213
CheckTask< NewFormulaType, ValueType > substituteFormula(NewFormulaType const &newFormula) const
Copies the check task from the source while replacing the formula with the new one.
Definition CheckTask.h:54
FormulaType const & getFormula() const
Retrieves the formula from this task.
Definition CheckTask.h:142
Class to efficiently check a formula on a parametric model with different parameter instantiations.
Class to approximately check a formula on a parametric model for all parameter valuations within a re...
virtual RegionResult analyzeRegion(Environment const &env, AnnotatedRegion< ParametricType > &region, RegionResultHypothesis const &hypothesis=RegionResultHypothesis::Unknown, bool sampleVerticesOfRegion=false) override
Analyzes the given region by means of Parameter Lifting.
typename RegionModelChecker< ParametricType >::CoefficientType CoefficientType
std::unique_ptr< CheckTask< storm::logic::Formula, ConstantType > > currentCheckTask
virtual void specifyUntilFormula(Environment const &env, CheckTask< storm::logic::UntilFormula, ConstantType > const &checkTask)
virtual void specifyReachabilityRewardFormula(Environment const &env, CheckTask< storm::logic::EventuallyFormula, ConstantType > const &checkTask)
std::unique_ptr< QuantitativeCheckResult< ConstantType > > getBound(Environment const &env, AnnotatedRegion< ParametricType > &region, storm::solver::OptimizationDirection const &dirForParameters)
Over-approximates the values within the given region for each state of the considered parametric mode...
virtual void specifyCumulativeRewardFormula(const CheckTask< storm::logic::CumulativeRewardFormula, ConstantType > &checkTask)
virtual storm::modelchecker::SparseInstantiationModelChecker< SparseModelType, ConstantType > & getInstantiationCheckerSAT(bool quantitative)
std::unique_ptr< CheckResult > check(Environment const &env, AnnotatedRegion< ParametricType > &region, storm::solver::OptimizationDirection const &dirForParameters)
Checks the specified formula on the given region by applying parameter lifting (Parameter choices are...
RegionResult sampleVertices(Environment const &env, storm::storage::ParameterRegion< ParametricType > const &region, RegionResult const &initialResult=RegionResult::Unknown)
Analyzes the 2^parameters corner points of the given region.
void specifyFormula(Environment const &env, CheckTask< storm::logic::Formula, ParametricType > const &checkTask)
virtual storm::modelchecker::SparseInstantiationModelChecker< SparseModelType, ConstantType > & getInstantiationCheckerVIO(bool quantitative)
virtual storm::modelchecker::SparseInstantiationModelChecker< SparseModelType, ConstantType > & getInstantiationChecker(bool quantitative)=0
virtual std::vector< ConstantType > computeQuantitativeValues(Environment const &env, AnnotatedRegion< ParametricType > &region, storm::solver::OptimizationDirection const &dirForParameters)=0
virtual CoefficientType getBoundAtInitState(Environment const &env, AnnotatedRegion< ParametricType > &region, storm::solver::OptimizationDirection const &dirForParameters) override
Over-approximates the value within the given region.
void updateKnownValueBoundInRegion(AnnotatedRegion< ParametricType > &region, storm::solver::OptimizationDirection dir, std::vector< ConstantType > const &newValues)
virtual void specifyReachabilityProbabilityFormula(Environment const &env, CheckTask< storm::logic::EventuallyFormula, ConstantType > const &checkTask)
typename RegionModelChecker< ParametricType >::Valuation Valuation
CheckTask< storm::logic::Formula, ConstantType > const & getCurrentCheckTask() const
virtual std::pair< CoefficientType, Valuation > getAndEvaluateGoodPoint(Environment const &env, AnnotatedRegion< ParametricType > &region, storm::solver::OptimizationDirection const &dirForParameters) override
Heuristically finds a point within the region and computes the value at the initial state for that po...
virtual void specifyBoundedUntilFormula(const CheckTask< storm::logic::BoundedUntilFormula, ConstantType > &checkTask)
#define STORM_LOG_INFO(message)
Definition logging.h:24
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
@ Incr
the result is monotonically increasing
@ Decr
the result is monotonically decreasing
@ Constant
the result is constant
RegionResult
The results for a single Parameter Region.
@ CenterSat
the formula is satisfied for the parameter Valuation that corresponds to the center point of the regi...
@ CenterIllDefined
the formula is ill-defined for the parameter Valuation that corresponds to the center point of the re...
@ AllSat
the formula is satisfied for all well-defined parameters in the given region
@ AllViolated
the formula is violated for all well-defined parameters in the given region
@ Unknown
the result is unknown
@ ExistsBoth
the formula is satisfied for some parameters but also violated for others
@ AllIllDefined
the formula is ill-defined for all parameters in the given region
@ CenterViolated
the formula is violated for the parameter Valuation that corresponds to the center point of the regio...
@ ExistsSat
the formula is satisfied for at least one parameter evaluation that lies in the given region
@ ExistsViolated
the formula is violated for at least one parameter evaluation that lies in the given region
@ ExistsIllDefined
the formula is ill-defined for at least one parameter evaluation that lies in the given region
RegionResultHypothesis
hypothesis for the result for a single Parameter Region
auto getOptimalValuationForMonotonicity(RegionType const &region, std::map< typename RegionType::VariableType, storm::analysis::MonotonicityKind > const &monotonicityResult, storm::OptimizationDirection dir)
bool constexpr maximize(OptimizationDirection d)
OptimizationDirection constexpr invert(OptimizationDirection d)
bool constexpr minimize(OptimizationDirection d)
ValueType infinity()
Definition constants.cpp:29
bool isInfinity(ValueType const &a)
TargetType convertNumber(SourceType const &number)
solver::OptimizationDirection OptimizationDirection