Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
RegionRefinementChecker.cpp
Go to the documentation of this file.
2
3#include <functional>
4#include <iterator>
5#include <queue>
6
17#include "storm/logic/Bound.h"
22
23namespace storm::modelchecker {
24
25template<typename ParametricType>
27 STORM_LOG_ASSERT(regionChecker != nullptr, "The region model checker must not be null.");
28 this->regionChecker = std::move(regionChecker);
29}
30
31template<typename ParametricType>
32bool RegionRefinementChecker<ParametricType>::canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel,
34 return regionChecker->canHandle(parametricModel, checkTask);
35}
36
37template<typename ParametricType>
38void RegionRefinementChecker<ParametricType>::specify(Environment const& env, std::shared_ptr<storm::models::ModelBase> parametricModel,
40 RegionSplittingStrategy splittingStrategy, std::set<VariableType> const& discreteVariables,
41 std::shared_ptr<MonotonicityBackend<ParametricType>> monotonicityBackend, bool allowModelSimplifications,
42 storm::pars::analysis::GraphPreservationStatus graphPreservationStatus) {
43 this->monotonicityBackend = monotonicityBackend ? monotonicityBackend : std::make_shared<MonotonicityBackend<ParametricType>>();
44 this->regionSplittingStrategy = std::move(splittingStrategy);
45 this->discreteVariables = std::move(discreteVariables);
46 this->graphPreservationStatus = graphPreservationStatus;
47 if (this->regionSplittingStrategy.heuristic == RegionSplittingStrategy::Heuristic::Default) {
48 regionSplittingStrategy.heuristic = RegionSplittingStrategy::Heuristic::EstimateBased;
49 }
50 // Potentially determine the kind of region split estimate to generate
51 if (regionSplittingStrategy.heuristic == RegionSplittingStrategy::Heuristic::EstimateBased) {
52 if (regionSplittingStrategy.estimateKind.has_value()) {
53 STORM_LOG_THROW(regionChecker->isRegionSplitEstimateKindSupported(regionSplittingStrategy.estimateKind.value(), checkTask),
54 storm::exceptions::NotSupportedException, "The specified region split estimate kind is not supported by the region model checker.");
55 } else {
56 regionSplittingStrategy.estimateKind = regionChecker->getDefaultRegionSplitEstimateKind(checkTask);
57 STORM_LOG_ASSERT(regionChecker->isRegionSplitEstimateKindSupported(regionSplittingStrategy.estimateKind.value(), checkTask),
58 "The region model checker does not support its default region split estimate kind.");
59 }
60 } else {
61 regionSplittingStrategy.estimateKind = std::nullopt; // do not compute estimates
62 }
63
64 regionChecker->specify(env, parametricModel, checkTask, regionSplittingStrategy.estimateKind, monotonicityBackend, allowModelSimplifications,
65 graphPreservationStatus);
66}
67
68template<typename T>
70 public:
71 PartitioningProgress(T const totalArea, uint64_t delay, T const coverageThreshold = storm::utility::zero<T>())
72 : totalArea(totalArea),
73 coverageThreshold(coverageThreshold),
74 fractionOfUndiscoveredArea(storm::utility::one<T>()),
75 fractionOfAllSatArea(storm::utility::zero<T>()),
76 fractionOfAllViolatedArea(storm::utility::zero<T>()),
77 progress("% covered area", delay) {
78 progress.setMaxCount(100 - asPercentage(coverageThreshold));
79 progress.startNewMeasurement(0u);
80 }
81
82 uint64_t getUndiscoveredPercentage() const {
83 return asPercentage(fractionOfUndiscoveredArea);
84 }
85
87 return fractionOfUndiscoveredArea <= coverageThreshold;
88 }
89
90 T addDiscoveredArea(T const& area) {
91 auto addedFraction = area / totalArea;
92 fractionOfUndiscoveredArea -= addedFraction;
93 progress.updateProgress(100 - getUndiscoveredPercentage());
94 return addedFraction;
95 }
96
97 void addAllSatArea(T const& area) {
98 fractionOfAllSatArea += addDiscoveredArea(area);
99 }
100
101 void addAllViolatedArea(T const& area) {
102 fractionOfAllViolatedArea += addDiscoveredArea(area);
103 }
104
105 void addAllIllDefinedArea(T const& area) {
106 fractionOfAllIllDefinedArea += addDiscoveredArea(area);
107 }
108
109 private:
110 static uint64_t asPercentage(T const& value) {
112 }
113
114 T const totalArea;
115 T const coverageThreshold;
116 T fractionOfUndiscoveredArea;
117 T fractionOfAllSatArea;
118 T fractionOfAllViolatedArea;
119 T fractionOfAllIllDefinedArea;
121};
122
123template<typename ParametricType>
124std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ParametricType>> RegionRefinementChecker<ParametricType>::performRegionPartitioning(
125 Environment const& env, storm::storage::ParameterRegion<ParametricType> const& region, std::optional<ParametricType> coverageThreshold,
126 std::optional<uint64_t> depthThreshold, RegionResultHypothesis const& hypothesis, uint64_t monThresh) {
127 STORM_LOG_INFO("Applying Region Partitioning on region: " << region.toString(true) << " .");
128
130 region.area(), env.solver().getShowProgressDelay(),
132
133 // Holds the initial region as well as all considered (sub)-regions and their annotations as a tree
135
136 // FIFO queue storing the current leafs of the region tree with neither allSat nor allViolated
137 // As we currently split regions in the center, a FIFO queue will ensure that regions with a larger area are processed first.
138 std::queue<std::reference_wrapper<AnnotatedRegion<ParametricType>>> unprocessedRegions;
139 unprocessedRegions.emplace(rootRegion);
140
141 uint64_t numOfAnalyzedRegions{0u};
142 bool monotonicityInitialized{false};
143
144 // Region Refinement Loop
145 while (!progress.isCoverageThresholdReached() && !unprocessedRegions.empty()) {
146 auto& currentRegion = unprocessedRegions.front().get();
147 STORM_LOG_TRACE("Analyzing region #" << numOfAnalyzedRegions << " (Refinement depth " << currentRegion.refinementDepth << "; "
148 << progress.getUndiscoveredPercentage() << "% still unknown; " << unprocessedRegions.size()
149 << " regions unprocessed).");
150 unprocessedRegions.pop(); // can pop already here, since the rootRegion has ownership.
151 ++numOfAnalyzedRegions;
152
153 if (!monotonicityInitialized && currentRegion.refinementDepth >= monThresh) {
154 monotonicityInitialized = true;
155 monotonicityBackend->initializeMonotonicity(env, rootRegion);
156 // Propagate monotonicity (unless the currentRegion is the root)
157 if (currentRegion.refinementDepth > 0) {
158 rootRegion.propagateAnnotationsToSubregions(true);
159 }
160 }
161 if (monotonicityInitialized) {
162 monotonicityBackend->updateMonotonicity(env, currentRegion);
163 }
164
165 currentRegion.result = regionChecker->analyzeRegion(env, currentRegion, hypothesis);
166
167 if (currentRegion.result == RegionResult::AllSat) {
168 progress.addAllSatArea(currentRegion.region.area());
169 } else if (currentRegion.result == RegionResult::AllViolated) {
170 progress.addAllViolatedArea(currentRegion.region.area());
171 } else if (currentRegion.result == RegionResult::AllIllDefined) {
172 // ill defined region => not graph-preserving
173 STORM_LOG_THROW(!storm::pars::analysis::isGraphPreserving(this->graphPreservationStatus), storm::exceptions::NotImplementedException,
174 "The region is not graph-preserving, but the selected region verification engine requires this assumption. Please use "
175 "--assume-graph-preserving false.");
176 progress.addAllIllDefinedArea(currentRegion.region.area());
177 } else {
178 // Split the region as long as the desired refinement depth is not reached.
179 if (!depthThreshold || currentRegion.refinementDepth < depthThreshold.value()) {
180 monotonicityBackend->updateMonotonicityBeforeSplitting(env, currentRegion);
181 auto splittingVariables = getSplittingVariables(currentRegion, Context::Partitioning);
182 STORM_LOG_INFO("Splitting on variables" << splittingVariables);
183 currentRegion.splitLeafNodeAtCenter(splittingVariables, this->discreteVariables, true);
184 for (auto& child : currentRegion.subRegions) {
185 unprocessedRegions.emplace(child);
186 }
187 }
188 }
189 }
190
191 // Prepare result
192 uint64_t numberOfRegionsKnownThroughMonotonicity{0};
193 std::vector<std::pair<storm::storage::ParameterRegion<ParametricType>, RegionResult>> result;
194 rootRegion.postOrderTraverseSubRegions([&result, &numberOfRegionsKnownThroughMonotonicity](auto& node) {
195 if (node.subRegions.empty()) {
196 if (node.resultKnownThroughMonotonicity) {
197 ++numberOfRegionsKnownThroughMonotonicity;
198 }
199 result.emplace_back(node.region, node.result);
200 }
201 });
202 auto const maxDepth = rootRegion.getMaxDepthOfSubRegions();
203 STORM_LOG_INFO("Region partitioning terminated after analyzing " << numOfAnalyzedRegions << " regions.\n\t" << numberOfRegionsKnownThroughMonotonicity
204 << " regions known through monotonicity.\n\tMaximum refinement depth: " << maxDepth
205 << ".\n\t" << progress.getUndiscoveredPercentage()
206 << "% of the parameter space are not covered.");
207
208 auto regionCopyForResult = region;
209 return std::make_unique<storm::modelchecker::RegionRefinementCheckResult<ParametricType>>(std::move(result), std::move(regionCopyForResult));
210}
211
212template<typename ParametricType>
213std::pair<typename RegionRefinementChecker<ParametricType>::ExtendedCoefficientType, typename storm::storage::ParameterRegion<ParametricType>::Valuation>
216 std::function<bool(ExtendedCoefficientType const&, ExtendedCoefficientType const&)> acceptGlobalBound,
217 std::function<bool(ExtendedCoefficientType const&)> rejectInstance) {
219
220 // Holds the initial region as well as all considered (sub)-regions and their annotations as a tree
222
223 // Priority Queue storing the regions that still need to be processed. Regions with a "good" bound are processed first
224 auto cmp = storm::solver::minimize(dir) ? [](AnnotatedRegion<ParametricType> const& lhs,
226 rhs) { return lhs.knownLowerValueBound.getExtendedValue() > rhs.knownLowerValueBound.getExtendedValue(); }
228 return lhs.knownUpperValueBound.getExtendedValue() < rhs.knownUpperValueBound.getExtendedValue();
229 };
230 std::priority_queue<std::reference_wrapper<AnnotatedRegion<ParametricType>>, std::vector<std::reference_wrapper<AnnotatedRegion<ParametricType>>>,
231 decltype(cmp)>
232 unprocessedRegions(cmp);
233 unprocessedRegions.push(rootRegion);
234
235 // Initialize Monotonicity
236 monotonicityBackend->initializeMonotonicity(env, rootRegion);
237
238 // Initialize result
239 auto valueValuation = regionChecker->getAndEvaluateGoodPoint(env, rootRegion, dir);
240 auto& value = valueValuation.first;
241 if (rejectInstance(value)) {
242 return valueValuation;
243 }
244
245 // Helper functions to check if a given result is better than the currently known result
246 auto isBetterThanValue = [&value, &dir](auto const& newValue) { return storm::solver::minimize(dir) ? newValue < value : newValue > value; };
247 // acceptGlobalBound is the opposite of this
248
249 // Region Refinement Loop
250 uint64_t numOfAnalyzedRegions{0u};
251 while (!unprocessedRegions.empty()) {
252 auto& currentRegion = unprocessedRegions.top().get();
253 ExtendedCoefficientType currentBound =
254 storm::solver::minimize(dir) ? currentRegion.knownLowerValueBound.getExtendedValue() : currentRegion.knownUpperValueBound.getExtendedValue();
255 STORM_LOG_TRACE("Analyzing region #" << numOfAnalyzedRegions << " (Refinement depth " << currentRegion.refinementDepth << "; "
256 << progress.getUndiscoveredPercentage() << "% still unknown; " << unprocessedRegions.size()
257 << " regions unprocessed). Best known value: " << value << ".");
258 unprocessedRegions.pop(); // can pop already here, since the rootRegion has ownership.
259 ++numOfAnalyzedRegions;
260
261 monotonicityBackend->updateMonotonicity(env, currentRegion);
262
263 // Compute the bound for this region (unless the known bound is already too weak)
264 if (!acceptGlobalBound(value, currentBound)) {
265 // Improve over-approximation of extremal value (within this region)
266 currentBound = regionChecker->getBoundAtInitState(env, currentRegion, dir);
267 if (storm::solver::minimize(dir)) {
268 currentRegion.knownLowerValueBound &= currentBound;
269 } else {
270 currentRegion.knownUpperValueBound &= currentBound;
271 }
272 }
273
274 // Process the region if the bound is promising
275 if (!acceptGlobalBound(value, currentBound)) {
276 // Improve (global) under-approximation of extremal value
277 // Check whether this region contains a new 'good' value and set this value if that is the case
278 auto [currValue, currValuation] = regionChecker->getAndEvaluateGoodPoint(env, currentRegion, dir);
279 if (isBetterThanValue(currValue)) {
280 valueValuation = {currValue, currValuation};
281 if (rejectInstance(currValue)) {
282 STORM_LOG_INFO("Found rejecting instance " << currValuation << " with value " << currValue);
283 return valueValuation;
284 }
285 }
286 }
287
288 // Trigger region-splitting if over- and under-approximation are still too far apart
289 if (!acceptGlobalBound(value, currentBound)) {
290 monotonicityBackend->updateMonotonicityBeforeSplitting(env, currentRegion);
291 auto splittingVariables = getSplittingVariables(currentRegion, Context::ExtremalValue);
292 STORM_LOG_INFO("Splitting on variables " << splittingVariables);
293 currentRegion.splitLeafNodeAtCenter(splittingVariables, this->discreteVariables, true);
294 for (auto& child : currentRegion.subRegions) {
295 unprocessedRegions.emplace(child);
296 }
297 } else {
298 progress.addDiscoveredArea(currentRegion.region.area());
299 }
300 }
301
302 STORM_LOG_INFO("Region partitioning for extremal value terminated after analyzing "
303 << numOfAnalyzedRegions << " regions.\n\t" << progress.getUndiscoveredPercentage() << "% of the parameter space are not covered.");
304 return valueValuation;
305}
306
307template<typename ParametricType>
308std::pair<typename RegionRefinementChecker<ParametricType>::ExtendedCoefficientType, typename storm::storage::ParameterRegion<ParametricType>::Valuation>
310 storm::solver::OptimizationDirection const& dir, ParametricType const& precision,
311 bool absolutePrecision, std::optional<storm::logic::Bound> const& boundInvariant) {
312 // Handle input precision
313 STORM_LOG_THROW(storm::utility::isConstant(precision), storm::exceptions::InvalidArgumentException,
314 "Precision must be a constant value. Got " << precision << " instead.");
316
317 auto acceptGlobalBound = [&](ExtendedCoefficientType const& value, ExtendedCoefficientType const& newValue) {
318 if (!storm::utility::isFinite(value)) {
319 return newValue == value;
320 }
321 ExtendedCoefficientType const usedPrecision = convertedPrecision * (absolutePrecision ? storm::utility::one<ExtendedCoefficientType>() : value);
322 return storm::solver::minimize(dir) ? newValue >= value - usedPrecision : newValue <= value + usedPrecision;
323 };
324
325 auto rejectInstance = [&](ExtendedCoefficientType const& currentValue) { return boundInvariant && !boundInvariant->isSatisfied(currentValue); };
326
327 return computeExtremalValueHelper(env, region, dir, acceptGlobalBound, rejectInstance);
328}
329
330template<typename ParametricType>
332 const storm::logic::Bound& bound) {
333 // Use the bound from the formula.
335 // We will try to violate the bound.
337 isLowerBound(bound.comparisonType) ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize;
338 // We pass the bound as an invariant; as soon as it is obtained, we can stop the search.
339 auto acceptGlobalBound = [&](ExtendedCoefficientType const&, ExtendedCoefficientType const& newValue) { return bound.isSatisfied(newValue); };
340
341 auto rejectInstance = [&](ExtendedCoefficientType const& currentValue) { return !bound.isSatisfied(currentValue); };
342
343 auto res = computeExtremalValueHelper(env, region, dir, acceptGlobalBound, rejectInstance).first;
344 STORM_LOG_INFO("Extremal value: " << res);
345 return storm::solver::minimize(dir) ? res >= valueToCheck : res <= valueToCheck;
346}
347
348template<typename ParametricType>
349std::set<typename RegionRefinementChecker<ParametricType>::VariableType> RegionRefinementChecker<ParametricType>::getSplittingVariablesEstimateBased(
350 AnnotatedRegion<ParametricType> const& region, Context context) const {
351 // If we can split on all variables, do that instead of requesting region split estimates
352 if (this->regionSplittingStrategy.maxSplitDimensions >= region.region.getVariables().size()) {
353 return region.region.getVariables();
354 }
355
356 auto const& estimates = regionChecker->obtainRegionSplitEstimates(region.region.getVariables());
357 std::vector<std::pair<VariableType, CoefficientType>> estimatesToSort;
358 estimatesToSort.reserve(region.region.getVariables().size());
359 STORM_LOG_ASSERT(estimates.size() == region.region.getVariables().size(), "Unexpected number of estimates.");
360 auto estimatesIter = estimates.begin();
361 for (auto const& param : region.region.getVariables()) {
362 estimatesToSort.push_back(std::make_pair(param, *estimatesIter++));
363 }
364
365 // Sort and insert largest n=maxSplitDimensions estimates
366 std::sort(estimatesToSort.begin(), estimatesToSort.end(), [](const auto& a, const auto& b) { return a.second > b.second; });
367
368 std::set<VariableType> splittingVars;
369 for (auto const& estimate : estimatesToSort) {
370 // Do not split on monotone parameters if finding an extremal value is the goal
371 if (context == Context::ExtremalValue && region.monotonicityAnnotation.getGlobalMonotonicityResult() &&
372 region.monotonicityAnnotation.getGlobalMonotonicityResult()->isMonotone(estimate.first)) {
373 continue;
374 }
375 // Do not split on parameters that are fixed
376 if (region.region.getDifference(estimate.first) == storm::utility::zero<CoefficientType>()) {
377 continue;
378 }
379 splittingVars.emplace(estimate.first);
380 if (splittingVars.size() == regionSplittingStrategy.maxSplitDimensions) {
381 break;
382 }
383 }
384 return splittingVars;
385}
386
387template<typename ParametricType>
388std::set<typename RegionRefinementChecker<ParametricType>::VariableType> RegionRefinementChecker<ParametricType>::getSplittingVariablesRoundRobin(
389 AnnotatedRegion<ParametricType> const& region, Context context) const {
390 // Perform round-robin based on the depth of the region, always split on max split dimensions
391 auto const& vars = region.region.getVariables();
392 auto varsIter = vars.begin();
393
394 std::advance(varsIter, (region.refinementDepth * this->regionSplittingStrategy.maxSplitDimensions) % vars.size());
395
396 auto loopPoint = varsIter;
397
398 std::set<VariableType> splittingVars;
399 do {
400 // Do not split on monotone parameters if finding an extremal value is the goal
401 if (context == Context::ExtremalValue && region.monotonicityAnnotation.getGlobalMonotonicityResult() &&
402 region.monotonicityAnnotation.getGlobalMonotonicityResult()->isMonotone(*varsIter)) {
403 continue;
404 }
405 splittingVars.emplace(*varsIter);
406 std::advance(varsIter, 1);
407 if (varsIter == vars.end()) {
408 varsIter = vars.begin();
409 }
410 } while (loopPoint != varsIter && splittingVars.size() < this->regionSplittingStrategy.maxSplitDimensions);
411
412 return splittingVars;
413}
414
415template<typename ParametricType>
416std::set<typename RegionRefinementChecker<ParametricType>::VariableType> RegionRefinementChecker<ParametricType>::getSplittingVariables(
417 AnnotatedRegion<ParametricType> const& region, Context context) const {
418 switch (regionSplittingStrategy.heuristic) {
420 return getSplittingVariablesEstimateBased(region, context);
422 return getSplittingVariablesRoundRobin(region, context);
424 default:
425 STORM_LOG_ERROR("Default strategy should have been populated.");
426 return {};
427 }
428}
429
431} // namespace storm::modelchecker
SolverEnvironment & solver()
uint64_t getShowProgressDelay() const
storm::RationalNumber evaluateAsRational() const
Evaluates the expression and returns the resulting rational number.
PartitioningProgress(T const totalArea, uint64_t delay, T const coverageThreshold=storm::utility::zero< T >())
bool canHandle(std::shared_ptr< storm::models::ModelBase > parametricModel, CheckTask< storm::logic::Formula, ParametricType > const &checkTask) const
typename storm::storage::ParameterRegion< ParametricType >::CoefficientType CoefficientType
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.
storm::utility::ExtendedValueType< CoefficientType > ExtendedCoefficientType
RegionRefinementChecker(std::unique_ptr< RegionModelChecker< ParametricType > > &&regionChecker)
std::unique_ptr< storm::modelchecker::RegionRefinementCheckResult< ParametricType > > performRegionPartitioning(Environment const &env, storm::storage::ParameterRegion< ParametricType > const &region, std::optional< ParametricType > coverageThreshold, std::optional< uint64_t > depthThreshold=std::nullopt, RegionResultHypothesis const &hypothesis=RegionResultHypothesis::Unknown, uint64_t monThresh=0)
Iteratively refines the region until the region analysis yields a conclusive result (AllSat or AllVio...
std::pair< ExtendedCoefficientType, 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)
Finds the extremal value within the given region and with the given precision.
void specify(Environment const &env, std::shared_ptr< storm::models::ModelBase > parametricModel, CheckTask< storm::logic::Formula, ParametricType > const &checkTask, RegionSplittingStrategy splittingStrategy=RegionSplittingStrategy(), std::set< VariableType > const &discreteVariables={}, std::shared_ptr< MonotonicityBackend< ParametricType > > monotonicityBackend={}, bool allowModelSimplifications=true, storm::pars::analysis::GraphPreservationStatus graphPreservationStatus=storm::pars::analysis::GraphPreservationStatus::GraphPreserving)
std::pair< ExtendedCoefficientType, Valuation > computeExtremalValueHelper(Environment const &env, storm::storage::ParameterRegion< ParametricType > const &region, storm::solver::OptimizationDirection const &dir, std::function< bool(ExtendedCoefficientType const &, ExtendedCoefficientType const &)> acceptGlobalBound, std::function< bool(ExtendedCoefficientType const &)> rejectInstance)
Finds the extremal value within the given region and with the given precision.
std::set< VariableType > const & getVariables() const
storm::utility::parametric::Valuation< ParametricType > Valuation
A class that provides convenience operations to display run times.
#define STORM_LOG_INFO(message)
Definition logging.h:34
#define STORM_LOG_TRACE(message)
Definition logging.h:22
#define STORM_LOG_ERROR(message)
Definition logging.h:36
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
RegionResult
The results for a single Parameter Region.
@ 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
@ AllIllDefined
the formula is ill-defined for all parameters in the given region
RegionResultHypothesis
hypothesis for the result for a single Parameter Region
GraphPreservationStatus
Describes to what extent a set of regions is known to be well-defined and to preserve the graph struc...
bool isGraphPreserving(GraphPreservationStatus status)
Returns whether the given status guarantees that the graph structure of the model is preserved.
bool constexpr minimize(OptimizationDirection d)
bool isFinite(ExtendedNumber< ValueType > const &value)
bool isConstant(ValueType const &)
ValueType zero()
Definition constants.cpp:26
ValueType one()
Definition constants.cpp:21
ValueType round(ValueType const &number)
TargetType convertNumber(SourceType const &number)
ComparisonType comparisonType
Definition Bound.h:17
storm::expressions::Expression threshold
Definition Bound.h:18
bool isSatisfied(ValueType const &compareValue) const
Definition Bound.cpp:9
void propagateAnnotationsToSubregions(bool allowDeleteAnnotationsOfThis)
storm::modelchecker::MonotonicityAnnotation< ParametricType > monotonicityAnnotation
Whether the result is known through monotonicity.
void postOrderTraverseSubRegions(std::function< void(AnnotatedRegion< ParametricType > &)> const &visitor)
storm::utility::Maximum< CoefficientType > knownLowerValueBound
storm::utility::Minimum< CoefficientType > knownUpperValueBound
Region const region
The subregions of this region.