Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
RegionModelChecker.cpp
Go to the documentation of this file.
1#include <queue>
2#include <sstream>
3#include <vector>
4
7
9
12
16
20
21namespace storm {
22namespace modelchecker {
23
24template<typename ParametricType>
26 // Intentionally left empty
27}
28
29template<typename ParametricType>
30std::unique_ptr<storm::modelchecker::RegionCheckResult<ParametricType>> RegionModelChecker<ParametricType>::analyzeRegions(
31 Environment const& env, std::vector<storm::storage::ParameterRegion<ParametricType>> const& regions, std::vector<RegionResultHypothesis> const& hypotheses,
32 bool sampleVerticesOfRegion) {
33 STORM_LOG_THROW(regions.size() == hypotheses.size(), storm::exceptions::InvalidArgumentException,
34 "The number of regions and the number of hypotheses do not match");
35 std::vector<std::pair<storm::storage::ParameterRegion<ParametricType>, storm::modelchecker::RegionResult>> result;
36
37 auto hypothesisIt = hypotheses.begin();
38 for (auto const& region : regions) {
40 analyzeRegion(env, region, *hypothesisIt, storm::modelchecker::RegionResult::Unknown, sampleVerticesOfRegion);
41 result.emplace_back(region, regionRes);
42 ++hypothesisIt;
43 }
44
45 return std::make_unique<storm::modelchecker::RegionCheckResult<ParametricType>>(std::move(result));
46}
47
48template<typename ParametricType>
50 storm::solver::OptimizationDirection const& dirForParameters) {
51 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "The selected region model checker does not support this functionality.");
52 return storm::utility::zero<ParametricType>();
53}
54
55template<typename ParametricType>
56std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ParametricType>> RegionModelChecker<ParametricType>::performRegionRefinement(
57 Environment const& env, storm::storage::ParameterRegion<ParametricType> const& region, boost::optional<ParametricType> const& coverageThreshold,
58 boost::optional<uint64_t> depthThreshold, RegionResultHypothesis const& hypothesis, uint64_t monThresh) {
59 STORM_LOG_INFO("Applying refinement on region: " << region.toString(true) << " .");
61 auto thresholdAsCoefficient =
62 coverageThreshold ? storm::utility::convertNumber<CoefficientType>(coverageThreshold.get()) : storm::utility::zero<CoefficientType>();
63 auto areaOfParameterSpace = region.area();
64 auto fractionOfUndiscoveredArea = storm::utility::one<CoefficientType>();
65 auto fractionOfAllSatArea = storm::utility::zero<CoefficientType>();
66 auto fractionOfAllViolatedArea = storm::utility::zero<CoefficientType>();
67 numberOfRegionsKnownThroughMonotonicity = 0;
68
69 // The resulting (sub-)regions
70 std::vector<std::pair<storm::storage::ParameterRegion<ParametricType>, RegionResult>> result;
71
72 // FIFO queues storing the data for the regions that we still need to process.
73 std::queue<std::pair<storm::storage::ParameterRegion<ParametricType>, RegionResult>> unprocessedRegions;
74
75 std::queue<uint64_t> refinementDepths;
76 unprocessedRegions.emplace(region, RegionResult::Unknown);
77 refinementDepths.push(0);
78
79 uint_fast64_t numOfAnalyzedRegions = 0;
80 CoefficientType displayedProgress = storm::utility::zero<CoefficientType>();
82 STORM_PRINT_AND_LOG("Progress (solved fraction) :\n" << "0% [");
83 while (displayedProgress < storm::utility::one<CoefficientType>() - thresholdAsCoefficient) {
85 displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
86 }
87 while (displayedProgress < storm::utility::one<CoefficientType>()) {
89 displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
90 }
91 STORM_PRINT_AND_LOG("] 100%\n" << " [");
92 displayedProgress = storm::utility::zero<CoefficientType>();
93 }
95 // NORMAL WHILE LOOP
96 uint64_t currentDepth = refinementDepths.front();
97 while ((!useMonotonicity || currentDepth < monThresh) && fractionOfUndiscoveredArea > thresholdAsCoefficient && !unprocessedRegions.empty()) {
98 assert(unprocessedRegions.size() == refinementDepths.size());
99 STORM_LOG_INFO("Analyzing region #" << numOfAnalyzedRegions << " (Refinement depth " << currentDepth << "; "
100 << storm::utility::convertNumber<double>(fractionOfUndiscoveredArea) * 100 << "% still unknown)");
101 auto& currentRegion = unprocessedRegions.front().first;
102 auto& res = unprocessedRegions.front().second;
103 std::shared_ptr<storm::analysis::Order> order;
104 std::shared_ptr<storm::analysis::LocalMonotonicityResult<VariableType>> localMonotonicityResult;
105 res = analyzeRegion(env, currentRegion, hypothesis, res, false);
107 switch (res) {
109 fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace;
110 fractionOfAllSatArea += currentRegion.area() / areaOfParameterSpace;
111 result.push_back(std::move(unprocessedRegions.front()));
112 break;
114 fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace;
115 fractionOfAllViolatedArea += currentRegion.area() / areaOfParameterSpace;
116 result.push_back(std::move(unprocessedRegions.front()));
117 break;
118 default:
119 // Split the region as long as the desired refinement depth is not reached.
120 if (!depthThreshold || currentDepth < depthThreshold.get()) {
121 std::vector<storm::storage::ParameterRegion<ParametricType>> newRegions;
122 RegionResult initResForNewRegions = (res == RegionResult::CenterSat)
126 currentRegion.split(currentRegion.getCenterPoint(), newRegions);
127 for (auto& newRegion : newRegions) {
128 unprocessedRegions.emplace(std::move(newRegion), initResForNewRegions);
129 refinementDepths.push(currentDepth + 1);
131
132 } else {
133 // If the region is not further refined, it is still added to the result
134 result.push_back(std::move(unprocessedRegions.front()));
135 }
136 break;
137 }
138 ++numOfAnalyzedRegions;
139 unprocessedRegions.pop();
140 refinementDepths.pop();
142 while (displayedProgress < storm::utility::one<CoefficientType>() - fractionOfUndiscoveredArea) {
144 displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
145 }
146 }
147 currentDepth = refinementDepths.front();
148 }
149
150 // FIFO queues for the order and local monotonicity results
151 std::queue<std::shared_ptr<storm::analysis::Order>> orders;
152 std::queue<std::shared_ptr<storm::analysis::LocalMonotonicityResult<VariableType>>> localMonotonicityResults;
153 std::shared_ptr<storm::analysis::Order> order;
154 std::shared_ptr<storm::analysis::LocalMonotonicityResult<VariableType>> localMonotonicityResult;
155 if (useMonotonicity && fractionOfUndiscoveredArea > thresholdAsCoefficient && !unprocessedRegions.empty()) {
156 storm::utility::Stopwatch monWatch(true);
157
158 orders.emplace(extendOrder(nullptr, region));
159 assert(orders.front() != nullptr);
160 auto monRes = std::shared_ptr<storm::analysis::LocalMonotonicityResult<VariableType>>(
161 new storm::analysis::LocalMonotonicityResult<VariableType>(orders.front()->getNumberOfStates()));
162 extendLocalMonotonicityResult(region, orders.front(), monRes);
163 localMonotonicityResults.emplace(monRes);
164 order = orders.front();
165 localMonotonicityResult = localMonotonicityResults.front();
166
167 if (!order->getDoneBuilding()) {
168 // we need to use copies for both order and local mon res
169 while (unprocessedRegions.size() > orders.size()) {
170 orders.emplace(order->copy());
171 localMonotonicityResults.emplace(localMonotonicityResult->copy());
172 }
173 } else if (!localMonotonicityResult->isDone()) {
174 // the order will not change anymore
175 while (unprocessedRegions.size() > orders.size()) {
176 orders.emplace(order);
177 localMonotonicityResults.emplace(localMonotonicityResult->copy());
178 }
179 } else {
180 // both will not change anymore
181 while (unprocessedRegions.size() > orders.size()) {
182 orders.emplace(order);
183 localMonotonicityResults.emplace(localMonotonicityResult);
184 }
185 }
186 monWatch.stop();
187 STORM_PRINT("\nTime for orderBuilding and monRes initialization: " << monWatch << ".\n\n");
188 }
189 bool useSameOrder = useMonotonicity && order->getDoneBuilding();
190 bool useSameLocalMonotonicityResult = useSameOrder && localMonotonicityResult->isDone();
191
192 // USEMON WHILE LOOP
193 while (useMonotonicity && fractionOfUndiscoveredArea > thresholdAsCoefficient && !unprocessedRegions.empty()) {
194 assert((useSameLocalMonotonicityResult && localMonotonicityResults.size() == 1) || unprocessedRegions.size() == localMonotonicityResults.size());
195 assert((useSameOrder && orders.size() == 1) || unprocessedRegions.size() == orders.size());
196 assert(unprocessedRegions.size() == refinementDepths.size());
197 currentDepth = refinementDepths.front();
198 STORM_LOG_INFO("Analyzing region #" << numOfAnalyzedRegions << " (Refinement depth " << currentDepth << "; "
199 << storm::utility::convertNumber<double>(fractionOfUndiscoveredArea) * 100 << "% still unknown)");
200 auto& currentRegion = unprocessedRegions.front().first;
201 auto& res = unprocessedRegions.front().second;
202
203 assert(!orders.empty());
204 if (!useSameOrder) {
205 order = orders.front();
206 if (!order->getDoneBuilding()) {
207 extendOrder(order, currentRegion);
208 }
209 }
210 if (!useSameLocalMonotonicityResult) {
211 localMonotonicityResult = localMonotonicityResults.front();
212 if (!localMonotonicityResult->isDone()) {
213 extendLocalMonotonicityResult(currentRegion, order, localMonotonicityResult);
214 }
215 }
216
217 res = analyzeRegion(env, currentRegion, hypothesis, res, false, localMonotonicityResult);
218
219 switch (res) {
221 fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace;
222 fractionOfAllSatArea += currentRegion.area() / areaOfParameterSpace;
223 STORM_LOG_INFO("Region " << unprocessedRegions.front() << " is AllSat");
224 result.push_back(std::move(unprocessedRegions.front()));
225 break;
227 fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace;
228 fractionOfAllViolatedArea += currentRegion.area() / areaOfParameterSpace;
229 STORM_LOG_INFO("Region " << unprocessedRegions.front() << " is AllViolated");
230
231 result.push_back(std::move(unprocessedRegions.front()));
232 break;
233 default:
234 // Split the region as long as the desired refinement depth is not reached.
235 if (!depthThreshold || currentDepth < depthThreshold.get()) {
236 std::vector<storm::storage::ParameterRegion<ParametricType>> newRegions;
237 RegionResult initResForNewRegions = (res == RegionResult::CenterSat)
240
241 std::vector<storm::storage::ParameterRegion<ParametricType>> newKnownRegions;
242 // Only split in (non)monotone vars
243 splitSmart(currentRegion, newRegions, *(localMonotonicityResult->getGlobalMonotonicityResult()), false);
244 assert(newRegions.size() != 0);
245
246 initResForNewRegions = (res == RegionResult::CenterSat)
249 bool first = true;
250 for (auto& newRegion : newRegions) {
251 if (!useSameOrder) {
252 if (first) {
253 orders.emplace(order);
254 localMonotonicityResults.emplace(localMonotonicityResult);
255 first = false;
256 } else {
257 if (!order->getDoneBuilding()) {
258 // we need to use copies for both order and local mon res
259 orders.emplace(order->copy());
260 localMonotonicityResults.emplace(localMonotonicityResult->copy());
261 } else if (!localMonotonicityResult->isDone()) {
262 // the order will not change anymore
263 orders.emplace(order);
264 localMonotonicityResults.emplace(localMonotonicityResult->copy());
265 } else {
266 // both will not change anymore
267 orders.emplace(order);
268 localMonotonicityResults.emplace(localMonotonicityResult);
269 }
270 }
271 } else if (!useSameLocalMonotonicityResult) {
272 if (first) {
273 localMonotonicityResults.emplace(localMonotonicityResult);
274 first = false;
275 } else {
276 if (!localMonotonicityResult->isDone()) {
277 localMonotonicityResults.emplace(localMonotonicityResult->copy());
278 } else {
279 localMonotonicityResults.emplace(localMonotonicityResult);
280 }
281 }
282 }
283 unprocessedRegions.emplace(std::move(newRegion), initResForNewRegions);
284 refinementDepths.push(currentDepth + 1);
285 }
286 } else {
287 // If the region is not further refined, it is still added to the result
288 result.push_back(std::move(unprocessedRegions.front()));
289 }
290 break;
291 }
292
293 ++numOfAnalyzedRegions;
294 unprocessedRegions.pop();
295 refinementDepths.pop();
296 if (!useSameOrder) {
297 orders.pop();
298 }
299 if (!useSameLocalMonotonicityResult) {
300 localMonotonicityResults.pop();
301 }
302
304 while (displayedProgress < storm::utility::one<CoefficientType>() - fractionOfUndiscoveredArea) {
306 displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
307 }
308 }
309 }
310
311 // Add the still unprocessed regions to the result
312 while (!unprocessedRegions.empty()) {
313 result.push_back(std::move(unprocessedRegions.front()));
314 unprocessedRegions.pop();
315 }
316
318 while (displayedProgress < storm::utility::one<CoefficientType>()) {
320 displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
321 }
322 STORM_PRINT_AND_LOG("]\n");
323
324 STORM_PRINT_AND_LOG("Region Refinement Statistics:\n");
325 STORM_PRINT_AND_LOG(" Analyzed a total of " << numOfAnalyzedRegions << " regions.\n");
326
327 if (useMonotonicity) {
328 STORM_PRINT_AND_LOG(" " << numberOfRegionsKnownThroughMonotonicity << " regions where discovered with help of monotonicity.\n");
329 }
330 }
331
332 auto regionCopyForResult = region;
333 return std::make_unique<storm::modelchecker::RegionRefinementCheckResult<ParametricType>>(std::move(result), std::move(regionCopyForResult));
334}
335
336template<typename ParametricType>
338 storm::storage::ParameterRegion<ParametricType> const& region, std::shared_ptr<storm::analysis::Order> order,
339 std::shared_ptr<storm::analysis::LocalMonotonicityResult<VariableType>> localMonotonicityResult) {
340 STORM_LOG_WARN("Initializing local Monotonicity Results not implemented for RegionModelChecker.");
341}
342
343template<typename ParametricType>
344std::pair<ParametricType, typename storm::storage::ParameterRegion<ParametricType>::Valuation> RegionModelChecker<ParametricType>::computeExtremalValue(
346 ParametricType const& precision, bool absolutePrecision, std::optional<storm::logic::Bound> const& terminationBound) {
347 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Computing extremal values is not supported for this region model checker.");
348 return std::pair<ParametricType, typename storm::storage::ParameterRegion<ParametricType>::Valuation>();
349}
350
351template<typename ParametricType>
353 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Checking extremal values is not supported for this region model checker.");
354 return false;
355}
356
357template<typename ParametricType>
361
362template<typename ParametricType>
363std::map<typename RegionModelChecker<ParametricType>::VariableType, double> RegionModelChecker<ParametricType>::getRegionSplitEstimate() const {
364 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Region split estimation is not supported by this region model checker.");
365 return std::map<typename RegionModelChecker<ParametricType>::VariableType, double>();
366}
367
368template<typename ParametricType>
369std::shared_ptr<storm::analysis::Order> RegionModelChecker<ParametricType>::extendOrder(std::shared_ptr<storm::analysis::Order> order,
371 STORM_LOG_WARN("Extending order for RegionModelChecker not implemented");
372 // Does nothing
373 return order;
374}
375
376template<typename ParametricType>
378 STORM_LOG_WARN("Setting constant entries fo local monotonicity result not implemented");
379 // Does nothing
380}
381
382template<typename ParametricType>
384 STORM_LOG_WARN("Setting max splitting dimensions is not implemented for this model checker");
385}
386
387template<typename ParametricType>
389 STORM_LOG_WARN("Resetting max splitting dimensions is not implemented for this model checker");
390}
391
392template<typename ParametricType>
394 return useMonotonicity;
395}
396
397template<typename ParametricType>
399 return useBounds;
400}
401
402template<typename ParametricType>
404 return useOnlyGlobal;
405}
406
407template<typename ParametricType>
409 this->useMonotonicity = monotonicity;
410}
411
412template<typename ParametricType>
414 assert(!bounds || useMonotonicity);
415 this->useBounds = bounds;
416}
417
418template<typename ParametricType>
420 assert(!global || useMonotonicity);
421 this->useOnlyGlobal = global;
422}
423
424template<typename ParametricType>
426 std::vector<storm::storage::ParameterRegion<ParametricType>>& regionVector,
427 storm::analysis::MonotonicityResult<VariableType>& monRes, bool splitForExtremum) const {
428 STORM_LOG_WARN("Smart splitting for this model checker not implemented");
429 currentRegion.split(currentRegion.getCenterPoint(), regionVector);
430}
431
432template<typename ParametricType>
435 monotoneParameters) {
436 monotoneIncrParameters = std::move(monotoneParameters.first);
437 monotoneDecrParameters = std::move(monotoneParameters.second);
438}
439
440#ifdef STORM_HAVE_CARL
442#endif
443} // namespace modelchecker
444} // namespace storm
virtual void extendLocalMonotonicityResult(storm::storage::ParameterRegion< ParametricType > const &region, std::shared_ptr< storm::analysis::Order > order, std::shared_ptr< storm::analysis::LocalMonotonicityResult< VariableType > > localMonotonicityResult)
void setUseMonotonicity(bool monotonicity=true)
std::unique_ptr< storm::modelchecker::RegionRefinementCheckResult< ParametricType > > performRegionRefinement(Environment const &env, storm::storage::ParameterRegion< ParametricType > const &region, boost::optional< ParametricType > const &coverageThreshold, boost::optional< uint64_t > depthThreshold=boost::none, RegionResultHypothesis const &hypothesis=RegionResultHypothesis::Unknown, uint64_t monThresh=0)
Iteratively refines the region until the region analysis yields a conclusive result (AllSat or AllVio...
virtual void resetMaxSplitDimensions()
When splitting, split in every dimension.
virtual std::pair< ParametricType, typename storm::storage::ParameterRegion< ParametricType >::Valuation > computeExtremalValue(Environment const &env, storm::storage::ParameterRegion< ParametricType > const &region, storm::solver::OptimizationDirection const &dir, ParametricType const &precision, bool absolutePrecision, std::optional< storm::logic::Bound > const &boundInvariant=std::nullopt)
Finds the extremal value within the given region and with the given precision.
virtual bool verifyRegion(Environment const &env, storm::storage::ParameterRegion< ParametricType > const &region, storm::logic::Bound const &bound)
Checks whether the bound is satisfied on the complete region.
virtual std::shared_ptr< storm::analysis::Order > extendOrder(std::shared_ptr< storm::analysis::Order > order, storm::storage::ParameterRegion< ParametricType > region)
virtual void setMaxSplitDimensions(uint64_t)
When splitting, split in at most this many dimensions.
virtual ParametricType getBoundAtInitState(Environment const &env, storm::storage::ParameterRegion< ParametricType > const &region, storm::solver::OptimizationDirection const &dirForParameters)
virtual bool isRegionSplitEstimateSupported() const
Returns true if region split estimation (a) was enabled when model and check task have been specified...
storm::storage::ParameterRegion< SparseModelType::ValueType >::CoefficientType CoefficientType
virtual std::map< VariableType, double > getRegionSplitEstimate() const
Returns an estimate of the benefit of splitting the last checked region with respect to each paramete...
virtual void setConstantEntries(std::shared_ptr< storm::analysis::LocalMonotonicityResult< VariableType > > localMonotonicityResult)
void setMonotoneParameters(std::pair< std::set< typename storm::storage::ParameterRegion< ParametricType >::VariableType >, std::set< typename storm::storage::ParameterRegion< ParametricType >::VariableType > > monotoneParameters)
std::unique_ptr< storm::modelchecker::RegionCheckResult< ParametricType > > analyzeRegions(Environment const &env, std::vector< storm::storage::ParameterRegion< ParametricType > > const &regions, std::vector< RegionResultHypothesis > const &hypotheses, bool sampleVerticesOfRegion=false)
Analyzes the given regions.
virtual void splitSmart(storm::storage::ParameterRegion< ParametricType > &region, std::vector< storm::storage::ParameterRegion< ParametricType > > &regionVector, storm::analysis::MonotonicityResult< VariableType > &monRes, bool splitForExtremum) const
Valuation getCenterPoint() const
Returns the center point of this region.
CoefficientType area() const
Returns the area of this region.
std::string toString(bool boundariesAsDouble=false) const
storm::utility::parametric::VariableType< ParametricType >::type VariableType
void split(Valuation const &splittingPoint, std::vector< ParameterRegion< ParametricType > > &regionVector) const
Splits the region at the given point and inserts the resulting subregions at the end of the given vec...
A class that provides convenience operations to display run times.
Definition Stopwatch.h:14
void stop()
Stop stopwatch and add measured time to total time.
Definition Stopwatch.cpp:42
#define STORM_LOG_INFO(message)
Definition logging.h:29
#define STORM_LOG_WARN(message)
Definition logging.h:30
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
#define STORM_PRINT_AND_LOG(message)
Definition macros.h:68
#define STORM_PRINT(message)
Define the macros that print information and optionally also log it.
Definition macros.h:62
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...
@ AllSat
the formula is satisfied for all parameters in the given region
@ AllViolated
the formula is violated for all parameters in the given region
@ Unknown
the result is unknown
@ 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
RegionResultHypothesis
hypothesis for the result for a single Parameter Region
SettingsType const & getModule()
Get module.
LabParser.cpp.
Definition cli.cpp:18