Storm
A Modern Probabilistic Model Checker
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
QuantileHelper.cpp
Go to the documentation of this file.
2
3#include <boost/optional.hpp>
4#include <memory>
5#include <set>
6#include <vector>
7
9
20
23
26
27namespace storm {
28namespace modelchecker {
29namespace helper {
30namespace rewardbounded {
31
32template<typename ModelType>
33QuantileHelper<ModelType>::QuantileHelper(ModelType const& model, storm::logic::QuantileFormula const& quantileFormula)
34 : model(model), quantileFormula(quantileFormula) {
35 // Do all kinds of sanity check.
36 std::set<storm::expressions::Variable> quantileVariables;
37 for (auto const& quantileVariable : quantileFormula.getBoundVariables()) {
38 STORM_LOG_THROW(quantileVariables.count(quantileVariable) == 0, storm::exceptions::NotSupportedException,
39 "Quantile formula considers the same bound variable twice.");
40 quantileVariables.insert(quantileVariable);
41 }
42 STORM_LOG_THROW(quantileFormula.getSubformula().isProbabilityOperatorFormula(), storm::exceptions::NotSupportedException,
43 "Quantile formula needs probability operator inside. The formula " << quantileFormula << " is not supported.");
44 auto const& probOpFormula = quantileFormula.getSubformula().asProbabilityOperatorFormula();
45 STORM_LOG_THROW(probOpFormula.hasBound(), storm::exceptions::InvalidOperationException,
46 "Probability operator inside quantile formula needs to have a bound.");
47 STORM_LOG_THROW(!model.isNondeterministicModel() || probOpFormula.hasOptimalityType(), storm::exceptions::InvalidOperationException,
48 "Probability operator inside quantile formula needs to have an optimality type.");
49 STORM_LOG_WARN_COND(probOpFormula.getBound().comparisonType == storm::logic::ComparisonType::Greater ||
50 probOpFormula.getBound().comparisonType == storm::logic::ComparisonType::LessEqual,
51 "Probability operator inside quantile formula needs to have bound > or <=. The specified comparison type might lead to "
52 "non-termination."); // This has to do with letting bound variables approach infinity, e.g., Pr>0.7 [F "goal"] holds iff Pr>0.7 [F<=B
53 // "goal"] holds for some B.
54 STORM_LOG_THROW(probOpFormula.getSubformula().isBoundedUntilFormula(), storm::exceptions::NotSupportedException,
55 "Quantile formula needs bounded until probability operator formula as subformula. The formula " << quantileFormula << " is not supported.");
56 auto const& boundedUntilFormula = probOpFormula.getSubformula().asBoundedUntilFormula();
57 std::set<storm::expressions::Variable> boundVariables;
58 for (uint64_t dim = 0; dim < boundedUntilFormula.getDimension(); ++dim) {
59 storm::expressions::Expression boundExpression;
60 if (boundedUntilFormula.hasUpperBound(dim)) {
61 STORM_LOG_THROW(!boundedUntilFormula.hasLowerBound(dim), storm::exceptions::NotSupportedException,
62 "Interval bounds are not supported within quantile formulas.");
63 STORM_LOG_THROW(!boundedUntilFormula.isUpperBoundStrict(dim), storm::exceptions::NotSupportedException,
64 "Only non-strict upper reward bounds are supported for quantiles.");
65 boundExpression = boundedUntilFormula.getUpperBound(dim);
66 } else if (boundedUntilFormula.hasLowerBound(dim)) {
67 STORM_LOG_THROW(!boundedUntilFormula.isLowerBoundStrict(dim), storm::exceptions::NotSupportedException,
68 "Only non-strict lower reward bounds are supported for quantiles.");
69 boundExpression = boundedUntilFormula.getLowerBound(dim);
70 }
71 if (boundExpression.isInitialized() && boundExpression.containsVariables()) {
73 boundExpression.isVariable(), storm::exceptions::NotSupportedException,
74 "Non-trivial bound expressions such as '" << boundExpression << "' are not supported. Either specify a constant or a quantile variable.");
75 storm::expressions::Variable const& boundVariable = boundExpression.getBaseExpression().asVariableExpression().getVariable();
76 STORM_LOG_THROW(boundVariables.count(boundVariable) == 0, storm::exceptions::NotSupportedException,
77 "Variable " << boundExpression << " occurs at multiple reward bounds.");
78 boundVariables.insert(boundVariable);
79 STORM_LOG_THROW(quantileVariables.count(boundVariable) == 1, storm::exceptions::NotSupportedException,
80 "The formula contains undefined constant '" << boundExpression << "'.");
81 }
82 }
83}
84
86std::shared_ptr<storm::logic::ProbabilityOperatorFormula> transformBoundedUntilOperator(storm::logic::ProbabilityOperatorFormula const& boundedUntilOperator,
87 std::vector<BoundTransformation> const& transformations,
88 bool complementQuery = false) {
89 auto const& origBoundedUntil = boundedUntilOperator.getSubformula().asBoundedUntilFormula();
90 STORM_LOG_ASSERT(transformations.size() == origBoundedUntil.getDimension(),
91 "Tried to replace the bound of a dimension that is higher than the number of dimensions of the formula.");
92 std::vector<std::shared_ptr<storm::logic::Formula const>> leftSubformulas, rightSubformulas;
93 std::vector<boost::optional<storm::logic::TimeBound>> lowerBounds, upperBounds;
94 std::vector<storm::logic::TimeBoundReference> timeBoundReferences;
95
96 for (uint64_t dim = 0; dim < origBoundedUntil.getDimension(); ++dim) {
97 if (origBoundedUntil.hasMultiDimensionalSubformulas()) {
98 leftSubformulas.push_back(origBoundedUntil.getLeftSubformula(dim).asSharedPointer());
99 rightSubformulas.push_back(origBoundedUntil.getRightSubformula(dim).asSharedPointer());
100 }
101 timeBoundReferences.push_back(origBoundedUntil.getTimeBoundReference(dim));
102 if (transformations[dim] == BoundTransformation::None) {
103 if (origBoundedUntil.hasLowerBound(dim)) {
104 lowerBounds.push_back(storm::logic::TimeBound(origBoundedUntil.isLowerBoundStrict(dim), origBoundedUntil.getLowerBound(dim)));
105 } else {
106 lowerBounds.push_back(boost::none);
107 }
108 if (origBoundedUntil.hasUpperBound(dim)) {
109 upperBounds.push_back(storm::logic::TimeBound(origBoundedUntil.isUpperBoundStrict(dim), origBoundedUntil.getUpperBound(dim)));
110 } else {
111 upperBounds.push_back(boost::none);
112 }
113 } else {
114 // We need a zero expression in all other cases
116 if (origBoundedUntil.hasLowerBound(dim)) {
117 zero = origBoundedUntil.getLowerBound(dim).getManager().rational(0.0);
118 } else {
119 STORM_LOG_THROW(origBoundedUntil.hasUpperBound(dim), storm::exceptions::InvalidOperationException,
120 "The given bounded until formula has no cost-bound for one dimension.");
121 zero = origBoundedUntil.getUpperBound(dim).getManager().rational(0.0);
122 }
123 if (transformations[dim] == BoundTransformation::LessEqualZero) {
124 lowerBounds.push_back(boost::none);
125 upperBounds.push_back(storm::logic::TimeBound(false, zero));
126 } else {
127 STORM_LOG_ASSERT(transformations[dim] == BoundTransformation::GreaterZero || transformations[dim] == BoundTransformation::GreaterEqualZero,
128 "Unhandled bound transformation.");
129 lowerBounds.push_back(storm::logic::TimeBound(transformations[dim] == BoundTransformation::GreaterZero, zero));
130 upperBounds.push_back(boost::none);
131 }
132 }
133 }
134 std::shared_ptr<storm::logic::Formula> newBoundedUntil;
135 if (origBoundedUntil.hasMultiDimensionalSubformulas()) {
136 newBoundedUntil = std::make_shared<storm::logic::BoundedUntilFormula>(leftSubformulas, rightSubformulas, lowerBounds, upperBounds, timeBoundReferences);
137 } else {
138 newBoundedUntil = std::make_shared<storm::logic::BoundedUntilFormula>(origBoundedUntil.getLeftSubformula().asSharedPointer(),
139 origBoundedUntil.getRightSubformula().asSharedPointer(), lowerBounds, upperBounds,
140 timeBoundReferences);
141 }
142 storm::logic::OperatorInformation newOpInfo(boundedUntilOperator.getOperatorInformation().optimalityType, boundedUntilOperator.getBound());
143 if (complementQuery) {
144 newOpInfo.bound->comparisonType = storm::logic::invert(newOpInfo.bound->comparisonType);
145 }
146 return std::make_shared<storm::logic::ProbabilityOperatorFormula>(newBoundedUntil, newOpInfo);
147}
148
151 STORM_LOG_DEBUG("Increasing precision of underlying solver.");
152 auto factor = storm::utility::convertNumber<storm::RationalNumber, std::string>("0.1");
154 static_cast<storm::RationalNumber>(env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()).first.get() * factor));
155 env.solver().minMax().setPrecision(env.solver().minMax().getPrecision() * factor);
156}
157
162template<typename ValueType>
163std::pair<ValueType, ValueType> getLowerUpperBound(storm::Environment const& env, ValueType const& factor, ValueType const& value, bool minMax = true) {
164 ValueType prec;
165 bool relative;
166 if (minMax) {
167 prec = storm::utility::convertNumber<ValueType>(env.solver().minMax().getPrecision());
168 relative = env.solver().minMax().getRelativeTerminationCriterion();
169 } else {
170 prec =
171 storm::utility::convertNumber<ValueType>(env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()).first.get());
173 }
174 prec *= factor;
175 if (relative) {
176 ValueType one = storm::utility::one<ValueType>();
177 ValueType lower = value * (one / (prec + one));
178 ValueType upper = value * (one + prec / (prec + one));
179 return std::make_pair(lower, upper);
180 } else {
181 return std::pair<ValueType, ValueType>(value - prec, value + prec);
182 }
183}
184
185template<typename ModelType>
186uint64_t QuantileHelper<ModelType>::getDimension() const {
187 return quantileFormula.getSubformula().asProbabilityOperatorFormula().getSubformula().asBoundedUntilFormula().getDimension();
188}
189
190template<typename ModelType>
191storm::storage::BitVector QuantileHelper<ModelType>::getOpenDimensions() const {
192 auto const& boundedUntil = quantileFormula.getSubformula().asProbabilityOperatorFormula().getSubformula().asBoundedUntilFormula();
193 storm::storage::BitVector res(getDimension(), false);
194 for (uint64_t dim = 0; dim < getDimension(); ++dim) {
195 auto const& bound = boundedUntil.hasLowerBound(dim) ? boundedUntil.getLowerBound(dim) : boundedUntil.getUpperBound(dim);
196 if (bound.containsVariables()) {
197 res.set(dim, true);
198 }
199 }
200 return res;
201}
202
203template<typename ModelType>
204storm::expressions::Variable const& QuantileHelper<ModelType>::getVariableForDimension(uint64_t const& dim) const {
205 auto const& boundedUntil = quantileFormula.getSubformula().asProbabilityOperatorFormula().getSubformula().asBoundedUntilFormula();
206 return (boundedUntil.hasLowerBound(dim) ? boundedUntil.getLowerBound(dim) : boundedUntil.getUpperBound(dim))
207 .getBaseExpression()
208 .asVariableExpression()
209 .getVariable();
210}
211
212template<typename ModelType>
213std::vector<std::vector<typename ModelType::ValueType>> QuantileHelper<ModelType>::computeQuantile(Environment const& env) {
214 numCheckedEpochs = 0;
215 numPrecisionRefinements = 0;
216 swEpochAnalysis.reset();
217 swExploration.reset();
218 cachedSubQueryResults.clear();
219
220 std::vector<std::vector<ValueType>> result;
221 Environment envCpy = env; // It might be necessary to increase the precision during the computation
222 // Call the internal recursive function
223 auto internalResult = computeQuantile(envCpy, getOpenDimensions(), false);
224
225 // Translate the result by applying the scaling factors and permutation.
226 std::vector<uint64_t> permutation;
227 for (auto const& v : quantileFormula.getBoundVariables()) {
228 uint64_t openDim = 0;
229 for (auto dim : getOpenDimensions()) {
230 if (getVariableForDimension(dim) == v) {
231 permutation.push_back(openDim);
232 break;
233 }
234 ++openDim;
235 }
236 }
237 assert(permutation.size() == getOpenDimensions().getNumberOfSetBits());
238 for (auto const& costLimits : internalResult.first.getGenerator()) {
239 std::vector<ValueType> resultPoint;
240 for (auto const& dim : permutation) {
241 CostLimit const& cl = costLimits[dim];
242 resultPoint.push_back(cl.isInfinity() ? storm::utility::infinity<ValueType>()
243 : storm::utility::convertNumber<ValueType>(cl.get()) * internalResult.second[dim]);
244 }
245 result.push_back(resultPoint);
246 }
248 std::cout << "Number of checked epochs: " << numCheckedEpochs << '\n';
249 std::cout << "Number of required precision refinements: " << numPrecisionRefinements << '\n';
250 std::cout << "Time for epoch exploration: " << swExploration << " seconds.\n";
251 std::cout << "\tTime for epoch model analysis: " << swEpochAnalysis << " seconds.\n";
252 }
253 return result;
254}
255
256template<typename ModelType>
257std::pair<CostLimitClosure, std::vector<typename QuantileHelper<ModelType>::ValueType>> QuantileHelper<ModelType>::computeQuantile(
258 Environment& env, storm::storage::BitVector const& consideredDimensions, bool complementaryQuery) {
259 STORM_LOG_ASSERT(consideredDimensions.isSubsetOf(getOpenDimensions()),
260 "Considered dimensions for a quantile query should be a subset of the set of dimensions without a fixed bound.");
261
262 storm::storage::BitVector cacheKey = consideredDimensions;
263 cacheKey.resize(cacheKey.size() + 1, complementaryQuery);
264 auto cacheIt = cachedSubQueryResults.find(cacheKey);
265 if (cacheIt != cachedSubQueryResults.end()) {
266 return cacheIt->second;
267 }
268
269 auto boundedUntilOp = transformBoundedUntilOperator(quantileFormula.getSubformula().asProbabilityOperatorFormula(),
270 std::vector<BoundTransformation>(getDimension(), BoundTransformation::None), complementaryQuery);
271 std::set<storm::expressions::Variable> infinityVariables;
272 storm::storage::BitVector lowerBoundedDimensions(getDimension());
273 storm::storage::BitVector downwardClosedDimensions(getDimension());
274 bool hasLowerValueBound = storm::logic::isLowerBound(boundedUntilOp->getComparisonType());
275 for (auto d : getOpenDimensions()) {
276 if (consideredDimensions.get(d)) {
277 bool hasLowerCostBound = boundedUntilOp->getSubformula().asBoundedUntilFormula().hasLowerBound(d);
278 lowerBoundedDimensions.set(d, hasLowerCostBound);
279 downwardClosedDimensions.set(d, hasLowerCostBound == hasLowerValueBound);
280 } else {
281 infinityVariables.insert(getVariableForDimension(d));
282 }
283 }
284 downwardClosedDimensions = downwardClosedDimensions % consideredDimensions;
285 CostLimitClosure satCostLimits(downwardClosedDimensions), unsatCostLimits(~downwardClosedDimensions);
286
287 // Initialize the (un)sat cost limits to guarantee termination
288 bool onlyUpperCostBounds = lowerBoundedDimensions.empty();
289 bool onlyLowerCostBounds = lowerBoundedDimensions == consideredDimensions;
290 if (onlyUpperCostBounds || onlyLowerCostBounds) {
291 for (auto k : consideredDimensions) {
292 storm::storage::BitVector subQueryDimensions = consideredDimensions;
293 subQueryDimensions.set(k, false);
294 bool subQueryComplement = complementaryQuery != ((onlyUpperCostBounds && hasLowerValueBound) || (onlyLowerCostBounds && !hasLowerValueBound));
295 auto subQueryResult = computeQuantile(env, subQueryDimensions, subQueryComplement);
296 for (auto const& subQueryCostLimit : subQueryResult.first.getGenerator()) {
297 CostLimits initPoint;
298 uint64_t i = 0;
299 for (auto dim : consideredDimensions) {
300 if (dim == k) {
301 initPoint.push_back(CostLimit::infinity());
302 } else {
303 initPoint.push_back(subQueryCostLimit[i]);
304 ++i;
305 }
306 }
307 if (subQueryComplement == complementaryQuery) {
308 satCostLimits.insert(initPoint);
309 } else {
310 unsatCostLimits.insert(initPoint);
311 }
312 }
313 }
314 } else {
315 STORM_LOG_WARN("Quantile formula considers mixtures of upper and lower reward-bounds. Termination is not guaranteed.");
316 }
317
318 // Loop until the goal precision is reached.
319 STORM_LOG_DEBUG("Computing quantile for dimensions: " << consideredDimensions);
320 while (true) {
321 // initialize reward unfolding and data that will be needed for each epoch
322 MultiDimensionalRewardUnfolding<ValueType, true> rewardUnfolding(model, boundedUntilOp, infinityVariables);
323 if (computeQuantile(env, consideredDimensions, *boundedUntilOp, lowerBoundedDimensions, satCostLimits, unsatCostLimits, rewardUnfolding)) {
324 std::vector<ValueType> scalingFactors;
325 for (auto dim : consideredDimensions) {
326 scalingFactors.push_back(rewardUnfolding.getDimension(dim).scalingFactor);
327 }
328 std::pair<CostLimitClosure, std::vector<ValueType>> result(satCostLimits, scalingFactors);
329 cachedSubQueryResults.emplace(cacheKey, result);
330 return result;
331 }
332 STORM_LOG_WARN("Restarting quantile computation after " << swExploration << " seconds due to insufficient precision.");
333 ++numPrecisionRefinements;
335 }
336}
337
338bool getNextCandidateCostLimit(CostLimit const& candidateCostLimitSum, CostLimits& current) {
339 if (current.size() == 0) {
340 return false;
341 }
342 uint64_t iSum = current.front().get();
343 if (iSum == candidateCostLimitSum.get()) {
344 return false;
345 }
346 for (uint64_t i = 1; i < current.size(); ++i) {
347 iSum += current[i].get();
348 if (iSum == candidateCostLimitSum.get()) {
349 ++current[i - 1].get();
350 uint64_t newVal = current[i].get() - 1;
351 current[i].get() = 0;
352 current.back().get() = newVal;
353 return true;
354 }
355 }
356 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException,
357 "The entries of the current cost limit candidate do not sum up to the current candidate sum.");
358 return false;
359}
360
361bool translateEpochToCostLimits(EpochManager::Epoch const& epoch, EpochManager::Epoch const& startEpoch, storm::storage::BitVector const& consideredDimensions,
362 storm::storage::BitVector const& lowerBoundedDimensions, EpochManager const& epochManager, CostLimits& epochAsCostLimits) {
363 for (uint64_t dim = 0; dim < consideredDimensions.size(); ++dim) {
364 if (consideredDimensions.get(dim)) {
365 if (lowerBoundedDimensions.get(dim)) {
366 if (epochManager.isBottomDimension(epoch, dim)) {
367 epochAsCostLimits.push_back(CostLimit(0));
368 } else {
369 epochAsCostLimits.push_back(CostLimit(epochManager.getDimensionOfEpoch(epoch, dim) + 1));
370 }
371 } else {
372 if (epochManager.isBottomDimension(epoch, dim)) {
373 return false;
374 } else {
375 epochAsCostLimits.push_back(CostLimit(epochManager.getDimensionOfEpoch(epoch, dim)));
376 }
377 }
378 } else {
379 if (epochManager.isBottomDimension(epoch, dim)) {
380 if (!epochManager.isBottomDimension(startEpoch, dim)) {
381 return false;
382 }
383 } else if (epochManager.getDimensionOfEpoch(epoch, dim) != epochManager.getDimensionOfEpoch(startEpoch, dim)) {
384 return false;
385 }
386 }
387 }
388 return true;
389}
390
391template<typename ModelType>
393 storm::logic::ProbabilityOperatorFormula const& boundedUntilOperator,
394 storm::storage::BitVector const& lowerBoundedDimensions, CostLimitClosure& satCostLimits,
395 CostLimitClosure& unsatCostLimits, MultiDimensionalRewardUnfolding<ValueType, true>& rewardUnfolding) {
396 auto lowerBound = rewardUnfolding.getLowerObjectiveBound();
397 auto upperBound = rewardUnfolding.getUpperObjectiveBound();
398 std::vector<ValueType> x, b;
399 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> minMaxSolver; // Needed for MDP
400 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> linEqSolver; // Needed for DTMC
401 if (!model.isNondeterministicModel()) {
402 rewardUnfolding.setEquationSystemFormatForEpochModel(storm::solver::GeneralLinearEquationSolverFactory<ValueType>().getEquationProblemFormat(env));
403 }
404
405 swExploration.start();
406 bool progress = true;
407 for (CostLimit candidateCostLimitSum(0); progress; ++candidateCostLimitSum.get()) {
408 CostLimits currentCandidate(satCostLimits.dimension(), CostLimit(0));
409 if (!currentCandidate.empty()) {
410 currentCandidate.back() = candidateCostLimitSum;
411 }
412 // We can still have progress if one of the closures is empty and the other is not full.
413 // This ensures that we do not terminate too early in case that the (un)satCostLimits are initially non-empty.
414 progress = (satCostLimits.empty() && !unsatCostLimits.full()) || (unsatCostLimits.empty() && !satCostLimits.full());
415 do {
416 if (!satCostLimits.contains(currentCandidate) && !unsatCostLimits.contains(currentCandidate)) {
417 progress = true;
418 // Transform candidate cost limits to an appropriate start epoch
419 auto startEpoch = rewardUnfolding.getStartEpoch(true);
420 auto costLimitIt = currentCandidate.begin();
421 for (auto dim : consideredDimensions) {
422 if (lowerBoundedDimensions.get(dim)) {
423 if (costLimitIt->get() > 0) {
424 rewardUnfolding.getEpochManager().setDimensionOfEpoch(startEpoch, dim, costLimitIt->get() - 1);
425 } else {
426 rewardUnfolding.getEpochManager().setBottomDimension(startEpoch, dim);
427 }
428 } else {
429 rewardUnfolding.getEpochManager().setDimensionOfEpoch(startEpoch, dim, costLimitIt->get());
430 }
431 ++costLimitIt;
432 }
433 STORM_LOG_DEBUG("Checking start epoch " << rewardUnfolding.getEpochManager().toString(startEpoch) << ".");
434 auto epochSequence = rewardUnfolding.getEpochComputationOrder(startEpoch, true);
435 for (auto const& epoch : epochSequence) {
436 ++numCheckedEpochs;
437 swEpochAnalysis.start();
438 auto& epochModel = rewardUnfolding.setCurrentEpoch(epoch);
439 if (model.isNondeterministicModel()) {
440 rewardUnfolding.setSolutionForCurrentEpoch(
441 epochModel.analyzeSingleObjective(env, boundedUntilOperator.getOptimalityType(), x, b, minMaxSolver, lowerBound, upperBound));
442 } else {
443 rewardUnfolding.setSolutionForCurrentEpoch(epochModel.analyzeSingleObjective(env, x, b, linEqSolver, lowerBound, upperBound));
444 }
445 swEpochAnalysis.stop();
446
447 CostLimits epochAsCostLimits;
448 if (translateEpochToCostLimits(epoch, startEpoch, consideredDimensions, lowerBoundedDimensions, rewardUnfolding.getEpochManager(),
449 epochAsCostLimits)) {
450 ValueType currValue = rewardUnfolding.getInitialStateResult(epoch);
451 bool propertySatisfied;
452 if (env.solver().isForceSoundness()) {
453 ValueType sumOfEpochDimensions =
454 storm::utility::convertNumber<ValueType>(rewardUnfolding.getEpochManager().getSumOfDimensions(epoch) + 1);
455 auto lowerUpperValue = getLowerUpperBound(env, sumOfEpochDimensions, currValue);
456 propertySatisfied = boundedUntilOperator.getBound().isSatisfied(lowerUpperValue.first);
457 if (propertySatisfied != boundedUntilOperator.getBound().isSatisfied(lowerUpperValue.second)) {
458 // unclear result due to insufficient precision.
459 swExploration.stop();
460 return false;
461 }
462 } else {
463 propertySatisfied = boundedUntilOperator.getBound().isSatisfied(currValue);
464 }
465 if (propertySatisfied) {
466 satCostLimits.insert(epochAsCostLimits);
467 } else {
468 unsatCostLimits.insert(epochAsCostLimits);
469 }
470 }
471 }
472 }
473 } while (getNextCandidateCostLimit(candidateCostLimitSum, currentCandidate));
474 if (!progress) {
475 progress = !CostLimitClosure::unionFull(satCostLimits, unsatCostLimits);
476 }
477 }
478 swExploration.stop();
479 return true;
480}
481
482template class QuantileHelper<storm::models::sparse::Mdp<double>>;
483template class QuantileHelper<storm::models::sparse::Mdp<storm::RationalNumber>>;
484template class QuantileHelper<storm::models::sparse::Dtmc<double>>;
485template class QuantileHelper<storm::models::sparse::Dtmc<storm::RationalNumber>>;
486
487} // namespace rewardbounded
488} // namespace helper
489} // namespace modelchecker
490} // namespace storm
SolverEnvironment & solver()
storm::RationalNumber const & getPrecision() const
void setPrecision(storm::RationalNumber value)
bool const & getRelativeTerminationCriterion() const
MinMaxSolverEnvironment & minMax()
storm::solver::EquationSolverType const & getLinearEquationSolverType() const
void setLinearEquationSolverPrecision(boost::optional< storm::RationalNumber > const &newPrecision, boost::optional< bool > const &relativePrecision=boost::none)
std::pair< boost::optional< storm::RationalNumber >, boost::optional< bool > > getPrecisionOfLinearEquationSolver(storm::solver::EquationSolverType const &solverType) const
VariableExpression const & asVariableExpression() const
bool isVariable() const
Retrieves whether the expression is a variable.
bool containsVariables() const
Retrieves whether the expression contains a variable.
BaseExpression const & getBaseExpression() const
Retrieves the base expression underlying this expression object.
bool isInitialized() const
Checks whether the object encapsulates a base-expression.
Variable const & getVariable() const
Retrieves the variable associated with this expression.
BoundedUntilFormula & asBoundedUntilFormula()
Definition Formula.cpp:325
virtual bool isProbabilityOperatorFormula() const
Definition Formula.cpp:172
ProbabilityOperatorFormula & asProbabilityOperatorFormula()
Definition Formula.cpp:453
Bound const & getBound() const
OperatorInformation const & getOperatorInformation() const
storm::solver::OptimizationDirection const & getOptimalityType() const
std::vector< storm::expressions::Variable > const & getBoundVariables() const
Formula const & getSubformula() const
Formula const & getSubformula() const
static bool unionFull(CostLimitClosure const &first, CostLimitClosure const &second)
Returns true if the union of the two closures is full, i.e., contains every point.
bool isBottomDimension(Epoch const &epoch, uint64_t const &dimension) const
uint64_t getDimensionOfEpoch(Epoch const &epoch, uint64_t const &dimension) const
std::vector< std::vector< ValueType > > computeQuantile(Environment const &env)
QuantileHelper(ModelType const &model, storm::logic::QuantileFormula const &quantileFormula)
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
bool isSubsetOf(BitVector const &other) const
Checks whether all bits that are set in the current bit vector are also set in the given bit vector.
void resize(uint_fast64_t newLength, bool init=false)
Resizes the bit vector to hold the given new number of bits.
void set(uint_fast64_t index, bool value=true)
Sets the given truth value at the given index.
size_t size() const
Retrieves the number of bits this bit vector can store.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
#define STORM_LOG_WARN(message)
Definition logging.h:30
#define STORM_LOG_DEBUG(message)
Definition logging.h:23
#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
SFTBDDChecker::ValueType ValueType
bool isLowerBound(ComparisonType t)
ComparisonType invert(ComparisonType t)
std::pair< ValueType, ValueType > getLowerUpperBound(storm::Environment const &env, ValueType const &factor, ValueType const &value, bool minMax=true)
Computes a lower / upper bound on the actual result of a sound minmax or linear equation solver.
void increasePrecision(storm::Environment &env)
Increases the precision of solver results.
bool translateEpochToCostLimits(EpochManager::Epoch const &epoch, EpochManager::Epoch const &startEpoch, storm::storage::BitVector const &consideredDimensions, storm::storage::BitVector const &lowerBoundedDimensions, EpochManager const &epochManager, CostLimits &epochAsCostLimits)
std::shared_ptr< storm::logic::ProbabilityOperatorFormula > transformBoundedUntilOperator(storm::logic::ProbabilityOperatorFormula const &boundedUntilOperator, std::vector< BoundTransformation > const &transformations, bool complementQuery=false)
bool getNextCandidateCostLimit(CostLimit const &candidateCostLimitSum, CostLimits &current)
SettingsType const & getModule()
Get module.
LabParser.cpp.
Definition cli.cpp:18
bool isSatisfied(ValueType const &compareValue) const
Definition Bound.cpp:7
boost::optional< Bound > bound
boost::optional< storm::solver::OptimizationDirection > optimalityType