Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseDtmcParameterLiftingModelChecker.cpp
Go to the documentation of this file.
2
4
16#include "storm/utility/graph.h"
18
25
26namespace storm {
27namespace modelchecker {
29template<typename SparseModelType, typename ConstantType>
31 : SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>(
32 std::make_unique<storm::solver::GeneralMinMaxLinearEquationSolverFactory<ConstantType>>()) {
33 // Intentionally left empty
35
36template<typename SparseModelType, typename ConstantType>
39 : solverFactory(std::move(solverFactory)), solvingRequiresUpperRewardBounds(false), regionSplitEstimationsEnabled(false) {
40 // Intentionally left empty
42
43template<typename SparseModelType, typename ConstantType>
44bool SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel,
45 CheckTask<storm::logic::Formula, ValueType> const& checkTask) const {
46 bool result = parametricModel->isOfType(storm::models::ModelType::Dtmc);
47 result &= parametricModel->isSparseModel();
48 result &= parametricModel->supportsParameters();
49 auto dtmc = parametricModel->template as<SparseModelType>();
50 result &= static_cast<bool>(dtmc);
51 result &= checkTask.getFormula().isInFragment(storm::logic::reachability()
61 return result;
64template<typename SparseModelType, typename ConstantType>
66 std::shared_ptr<storm::models::ModelBase> parametricModel,
68 bool generateRegionSplitEstimates, bool allowModelSimplification) {
69 auto dtmc = parametricModel->template as<SparseModelType>();
70 monotonicityChecker = std::make_unique<storm::analysis::MonotonicityChecker<ValueType>>(dtmc->getTransitionMatrix());
71 specify_internal(env, dtmc, checkTask, generateRegionSplitEstimates, !allowModelSimplification);
73
74template<typename SparseModelType, typename ConstantType>
76 std::shared_ptr<SparseModelType> parametricModel,
78 bool generateRegionSplitEstimates, bool skipModelSimplification) {
79 STORM_LOG_ASSERT(this->canHandle(parametricModel, checkTask), "specified model and formula can not be handled by this.");
80
81 reset();
82
83 regionSplitEstimationsEnabled = generateRegionSplitEstimates;
84
85 if (skipModelSimplification) {
86 this->parametricModel = parametricModel;
87 this->specifyFormula(env, checkTask);
88 } else {
90 if (!simplifier.simplify(checkTask.getFormula())) {
91 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull.");
92 }
93 this->parametricModel = simplifier.getSimplifiedModel();
94 this->specifyFormula(env, checkTask.substituteFormula(*simplifier.getSimplifiedFormula()));
95 }
96}
97
98template<typename SparseModelType, typename ConstantType>
101 // get the step bound
102 STORM_LOG_THROW(!checkTask.getFormula().hasLowerBound(), storm::exceptions::NotSupportedException, "Lower step bounds are not supported.");
103 STORM_LOG_THROW(checkTask.getFormula().hasUpperBound(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with an upper bound.");
104 STORM_LOG_THROW(checkTask.getFormula().getTimeBoundReference().isStepBound(), storm::exceptions::NotSupportedException,
105 "Expected a bounded until formula with step bounds.");
106 stepBound = checkTask.getFormula().getUpperBound().evaluateAsInt();
107 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
108 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
109 if (checkTask.getFormula().isUpperBoundStrict()) {
110 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero.");
111 --(*stepBound);
112 }
113 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
114 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
115
116 // get the results for the subformulas
117 storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel);
118 STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) &&
119 propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()),
120 storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
121 storm::storage::BitVector phiStates =
122 std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
123 storm::storage::BitVector psiStates =
124 std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
125
126 // get the maybeStates
127 maybeStates = storm::utility::graph::performProbGreater0(this->parametricModel->getBackwardTransitions(), phiStates, psiStates, true, *stepBound);
128 maybeStates &= ~psiStates;
129
130 // set the result for all non-maybe states
131 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
132 storm::utility::vector::setVectorValues(resultsForNonMaybeStates, psiStates, storm::utility::one<ConstantType>());
133
134 // if there are maybestates, create the parameterLifter
135 if (!maybeStates.empty()) {
136 // Create the vector of one-step probabilities to go to target states.
137 std::vector<ValueType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(
138 storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), psiStates);
139 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ValueType, ConstantType>>(
140 this->parametricModel->getTransitionMatrix(), b, maybeStates, maybeStates, false, RegionModelChecker<ValueType>::isUseMonotonicitySet());
141 }
142
143 // We know some bounds for the results so set them
144 lowerResultBound = storm::utility::zero<ConstantType>();
145 upperResultBound = storm::utility::one<ConstantType>();
146 // No requirements for bounded formulas
147 solverFactory->setRequirementsChecked(true);
148
149 // For monotonicity checking
150 std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 =
151 storm::utility::graph::performProb01(this->parametricModel->getBackwardTransitions(), phiStates, psiStates);
152 this->orderExtender = storm::analysis::OrderExtender<ValueType, ConstantType>(&statesWithProbability01.second, &statesWithProbability01.first,
153 this->parametricModel->getTransitionMatrix());
154}
155
156template<typename SparseModelType, typename ConstantType>
159 // get the results for the subformulas
160 storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel);
161 STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) &&
162 propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()),
163 storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
164 storm::storage::BitVector phiStates =
165 std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
166 storm::storage::BitVector psiStates =
167 std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
168
169 // get the maybeStates
170 std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 =
171 storm::utility::graph::performProb01(this->parametricModel->getBackwardTransitions(), phiStates, psiStates);
172 maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second);
173
174 // set the result for all non-maybe states
175 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
176 storm::utility::vector::setVectorValues(resultsForNonMaybeStates, statesWithProbability01.second, storm::utility::one<ConstantType>());
177
178 // if there are maybestates, create the parameterLifter
179 if (!maybeStates.empty()) {
180 // Create the vector of one-step probabilities to go to target states.
181 std::vector<ValueType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(
182 storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), statesWithProbability01.second);
183 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ValueType, ConstantType>>(
184 this->parametricModel->getTransitionMatrix(), b, maybeStates, maybeStates, regionSplitEstimationsEnabled,
186 }
187
188 // We know some bounds for the results so set them
189 lowerResultBound = storm::utility::zero<ConstantType>();
190 upperResultBound = storm::utility::one<ConstantType>();
191
192 // The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations, every induced DTMC has the same graph
193 // structure).
194 auto req = solverFactory->getRequirements(env, true, true, boost::none, true);
195 req.clearBounds();
196 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
197 "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked.");
198 solverFactory->setRequirementsChecked(true);
199
200 this->orderExtender = storm::analysis::OrderExtender<ValueType, ConstantType>(&statesWithProbability01.second, &statesWithProbability01.first,
201 this->parametricModel->getTransitionMatrix());
202}
203
204template<typename SparseModelType, typename ConstantType>
207 // get the results for the subformula
208 storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel);
209 STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getSubformula()), storm::exceptions::NotSupportedException,
210 "Parameter lifting with non-propositional subformulas is not supported");
211 storm::storage::BitVector targetStates =
212 std::move(propositionalChecker.check(checkTask.getFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
213 // get the maybeStates
215 this->parametricModel->getBackwardTransitions(), storm::storage::BitVector(this->parametricModel->getNumberOfStates(), true), targetStates);
216 infinityStates.complement();
217 maybeStates = ~(targetStates | infinityStates);
218
219 // set the result for all the non-maybe states
220 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
221 storm::utility::vector::setVectorValues(resultsForNonMaybeStates, infinityStates, storm::utility::infinity<ConstantType>());
222
223 // if there are maybestates, create the parameterLifter
224 if (!maybeStates.empty()) {
225 // Create the reward vector
226 STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel->hasRewardModel(checkTask.getRewardModel())) ||
227 (!checkTask.isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()),
228 storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model.");
229
230 typename SparseModelType::RewardModelType const& rewardModel =
231 checkTask.isRewardModelSet() ? this->parametricModel->getRewardModel(checkTask.getRewardModel()) : this->parametricModel->getUniqueRewardModel();
232
233 std::vector<ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix());
234
235 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ValueType, ConstantType>>(
236 this->parametricModel->getTransitionMatrix(), b, maybeStates, maybeStates, regionSplitEstimationsEnabled);
237 }
238
239 // We only know a lower bound for the result
240 lowerResultBound = storm::utility::zero<ConstantType>();
241
242 // The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations, every induced DTMC has the same graph
243 // structure).
244 auto req = solverFactory->getRequirements(env, true, true, boost::none, true);
245 req.clearLowerBounds();
246 if (req.upperBounds()) {
247 solvingRequiresUpperRewardBounds = true;
248 req.clearUpperBounds();
249 }
250 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
251 "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked.");
252 solverFactory->setRequirementsChecked(true);
253}
254
255template<typename SparseModelType, typename ConstantType>
258 // Obtain the stepBound
259 stepBound = checkTask.getFormula().getBound().evaluateAsInt();
260 if (checkTask.getFormula().isBoundStrict()) {
261 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero.");
262 --(*stepBound);
263 }
264 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
265 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
266
267 // Every state is a maybeState
268 maybeStates = storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getColumnCount(), true);
269 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates());
270
271 // Create the reward vector
272 STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel->hasRewardModel(checkTask.getRewardModel())) ||
273 (!checkTask.isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()),
274 storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model.");
275 typename SparseModelType::RewardModelType const& rewardModel =
276 checkTask.isRewardModelSet() ? this->parametricModel->getRewardModel(checkTask.getRewardModel()) : this->parametricModel->getUniqueRewardModel();
277 std::vector<ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix());
278
279 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b,
280 maybeStates, maybeStates);
281
282 // We only know a lower bound for the result
283 lowerResultBound = storm::utility::zero<ConstantType>();
284
285 // No requirements for bounded reward formula
286 solverFactory->setRequirementsChecked(true);
287}
288
289template<typename SparseModelType, typename ConstantType>
292 if (!instantiationCheckerSAT) {
293 instantiationCheckerSAT =
294 std::make_unique<storm::modelchecker::SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>>(*this->parametricModel);
295 instantiationCheckerSAT->specifyFormula(this->currentCheckTask->template convertValueType<ValueType>());
296 instantiationCheckerSAT->setInstantiationsAreGraphPreserving(true);
297 }
298 return *instantiationCheckerSAT;
299}
300
301template<typename SparseModelType, typename ConstantType>
304 if (!instantiationCheckerVIO) {
305 instantiationCheckerVIO =
306 std::make_unique<storm::modelchecker::SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>>(*this->parametricModel);
307 instantiationCheckerVIO->specifyFormula(this->currentCheckTask->template convertValueType<ValueType>());
308 instantiationCheckerVIO->setInstantiationsAreGraphPreserving(true);
309 }
310 return *instantiationCheckerVIO;
311}
312
313template<typename SparseModelType, typename ConstantType>
316 if (!instantiationChecker) {
317 instantiationChecker =
318 std::make_unique<storm::modelchecker::SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>>(*this->parametricModel);
319 instantiationChecker->specifyFormula(this->currentCheckTask->template convertValueType<ValueType>());
320 instantiationChecker->setInstantiationsAreGraphPreserving(true);
321 }
322 return *instantiationChecker;
323}
324
325template<typename SparseModelType, typename ConstantType>
328 std::shared_ptr<storm::analysis::LocalMonotonicityResult<VariableType>> localMonotonicityResult) {
329 if (maybeStates.empty()) {
330 return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(resultsForNonMaybeStates);
331 }
332 parameterLifter->specifyRegion(region, dirForParameters);
333
334 if (stepBound) {
335 assert(*stepBound > 0);
336 x = std::vector<ConstantType>(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
337 auto multiplier = storm::solver::MultiplierFactory<ConstantType>().create(env, parameterLifter->getMatrix());
338 multiplier->repeatedMultiplyAndReduce(env, dirForParameters, x, &parameterLifter->getVector(), *stepBound);
339 } else {
340 auto solver = solverFactory->create(env, parameterLifter->getMatrix());
341 solver->setHasUniqueSolution();
342 solver->setHasNoEndComponents();
343 if (lowerResultBound)
344 solver->setLowerBound(lowerResultBound.get());
345 if (upperResultBound) {
346 solver->setUpperBound(upperResultBound.get());
347 } else if (solvingRequiresUpperRewardBounds) {
348 // For the min-case, we use DS-MPI, for the max-case variant 2 of the Baier et al. paper (CAV'17).
349 std::vector<ConstantType> oneStepProbs;
350 oneStepProbs.reserve(parameterLifter->getMatrix().getRowCount());
351 for (uint64_t row = 0; row < parameterLifter->getMatrix().getRowCount(); ++row) {
352 oneStepProbs.push_back(storm::utility::one<ConstantType>() - parameterLifter->getMatrix().getRowSum(row));
353 }
354 if (dirForParameters == storm::OptimizationDirection::Minimize) {
355 storm::modelchecker::helper::DsMpiMdpUpperRewardBoundsComputer<ConstantType> dsmpi(parameterLifter->getMatrix(), parameterLifter->getVector(),
356 oneStepProbs);
357 solver->setUpperBounds(dsmpi.computeUpperBounds());
358 } else {
359 storm::modelchecker::helper::BaierUpperRewardBoundsComputer<ConstantType> baier(parameterLifter->getMatrix(), parameterLifter->getVector(),
360 oneStepProbs);
361 solver->setUpperBound(baier.computeUpperBound());
362 }
363 }
364 solver->setTrackScheduler(true);
365
366 if (localMonotonicityResult != nullptr && !this->isOnlyGlobalSet()) {
367 storm::storage::BitVector choiceFixedForStates(parameterLifter->getRowGroupCount(), false);
368
369 bool useMinimize = storm::solver::minimize(dirForParameters);
370 if (useMinimize && !minSchedChoices) {
371 minSchedChoices = std::vector<uint_fast64_t>(parameterLifter->getRowGroupCount(), 0);
372 }
373 if (!useMinimize && !maxSchedChoices) {
374 maxSchedChoices = std::vector<uint_fast64_t>(parameterLifter->getRowGroupCount(), 0);
375 }
376
377 auto const& occuringVariables = parameterLifter->getOccurringVariablesAtState();
378 for (uint_fast64_t state = 0; state < parameterLifter->getRowGroupCount(); ++state) {
379 auto oldStateNumber = parameterLifter->getOriginalStateNumber(state);
380 auto& variables = occuringVariables.at(oldStateNumber);
381 // point at which we start with rows for this state
382
383 STORM_LOG_THROW(variables.size() <= 1, storm::exceptions::NotImplementedException,
384 "Using localMonRes not yet implemented for states with 2 or more variables, please run without --use-monotonicity");
385
386 bool allMonotone = true;
387 for (auto var : variables) {
388 auto monotonicity = localMonotonicityResult->getMonotonicity(oldStateNumber, var);
389
390 bool ignoreUpperBound = monotonicity == Monotonicity::Constant || (useMinimize && monotonicity == Monotonicity::Incr) ||
391 (!useMinimize && monotonicity == Monotonicity::Decr);
392 bool ignoreLowerBound =
393 !ignoreUpperBound && ((useMinimize && monotonicity == Monotonicity::Decr) || (!useMinimize && monotonicity == Monotonicity::Incr));
394 allMonotone &= (ignoreUpperBound || ignoreLowerBound);
395 if (ignoreLowerBound) {
396 if (useMinimize) {
397 minSchedChoices.get()[state] = 1;
398 } else {
399 maxSchedChoices.get()[state] = 1;
400 }
401 } else if (ignoreUpperBound) {
402 if (useMinimize) {
403 minSchedChoices.get()[state] = 0;
404 } else {
405 maxSchedChoices.get()[state] = 0;
406 }
407 }
408 }
409 if (allMonotone) {
410 choiceFixedForStates.set(state);
411 }
412 }
413 // We need to set the scheduler before we set the states for which the choices are fixed
414 if (storm::solver::minimize(dirForParameters) && minSchedChoices)
415 solver->setInitialScheduler(std::move(minSchedChoices.get()));
416 if (storm::solver::maximize(dirForParameters) && maxSchedChoices)
417 solver->setInitialScheduler(std::move(maxSchedChoices.get()));
418 solver->setSchedulerFixedForRowGroup(std::move(choiceFixedForStates));
419 } else {
420 if (storm::solver::minimize(dirForParameters) && minSchedChoices)
421 solver->setInitialScheduler(std::move(minSchedChoices.get()));
422 if (storm::solver::maximize(dirForParameters) && maxSchedChoices)
423 solver->setInitialScheduler(std::move(maxSchedChoices.get()));
424 }
425
426 if (this->currentCheckTask->isBoundSet() && solver->hasInitialScheduler()) {
427 // If we reach this point, we know that after applying the hint, the x-values can only become larger (if we maximize) or smaller (if we minimize).
428 std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond;
429 storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet()
430 ? this->parametricModel->getInitialStates() % maybeStates
431 : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true);
432 if (storm::solver::minimize(dirForParameters)) {
433 // Terminate if the value for ALL relevant states is already below the threshold
434 termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>>(
435 relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), false);
436 } else {
437 // Terminate if the value for ALL relevant states is already above the threshold
438 termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>>(
439 relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true);
440 }
441 solver->setTerminationCondition(std::move(termCond));
442 }
443
444 // Invoke the solver
445 x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
446 solver->solveEquations(env, dirForParameters, x, parameterLifter->getVector());
447 if (storm::solver::minimize(dirForParameters)) {
448 minSchedChoices = solver->getSchedulerChoices();
449 } else {
450 maxSchedChoices = solver->getSchedulerChoices();
451 }
452 if (isRegionSplitEstimateSupported()) {
453 computeRegionSplitEstimates(x, solver->getSchedulerChoices(), region, dirForParameters);
454 }
455 }
456
457 // Get the result for the complete model (including maybestates)
458 std::vector<ConstantType> result = resultsForNonMaybeStates;
459 auto maybeStateResIt = x.begin();
460 for (auto const& maybeState : maybeStates) {
461 result[maybeState] = *maybeStateResIt;
462 ++maybeStateResIt;
463 }
464 return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(std::move(result));
465}
466
467template<typename SparseModelType, typename ConstantType>
469 std::vector<ConstantType> const& quantitativeResult, std::vector<uint_fast64_t> const& schedulerChoices,
471 std::map<VariableType, double> deltaLower, deltaUpper;
472 for (auto const& p : region.getVariables()) {
473 deltaLower.insert(std::make_pair(p, 0.0));
474 deltaUpper.insert(std::make_pair(p, 0.0));
475 }
476 auto const& choiceValuations = parameterLifter->getRowLabels();
477 auto const& matrix = parameterLifter->getMatrix();
478 auto const& vector = parameterLifter->getVector();
479
480 std::vector<ConstantType> stateResults;
481 for (uint64_t state = 0; state < schedulerChoices.size(); ++state) {
482 uint64_t rowOffset = matrix.getRowGroupIndices()[state];
483 uint64_t optimalChoice = schedulerChoices[state];
484 auto const& optimalChoiceVal = choiceValuations[rowOffset + optimalChoice];
485 assert(optimalChoiceVal.getUnspecifiedParameters().empty());
486 stateResults.clear();
487 for (uint64_t row = rowOffset; row < matrix.getRowGroupIndices()[state + 1]; ++row) {
488 stateResults.push_back(matrix.multiplyRowWithVector(row, quantitativeResult) + vector[row]);
489 }
490 // Do this twice, once for upperbound once for lowerbound
491 bool checkUpperParameters = false;
492 do {
493 auto const& consideredParameters = checkUpperParameters ? optimalChoiceVal.getUpperParameters() : optimalChoiceVal.getLowerParameters();
494 for (auto const& p : consideredParameters) {
495 // Find the 'best' choice that assigns the parameter to the other bound
496 ConstantType bestValue = 0;
497 bool foundBestValue = false;
498 for (uint64_t choice = 0; choice < stateResults.size(); ++choice) {
499 if (choice != optimalChoice) {
500 auto const& otherBoundParsOfChoice = checkUpperParameters ? choiceValuations[rowOffset + choice].getLowerParameters()
501 : choiceValuations[rowOffset + choice].getUpperParameters();
502 if (otherBoundParsOfChoice.find(p) != otherBoundParsOfChoice.end()) {
503 ConstantType const& choiceValue = stateResults[choice];
504 if (!foundBestValue || (storm::solver::minimize(dirForParameters) ? choiceValue < bestValue : choiceValue > bestValue)) {
505 foundBestValue = true;
506 bestValue = choiceValue;
507 }
508 }
509 }
510 }
511 auto optimal = storm::utility::convertNumber<double>(stateResults[optimalChoice]);
512 auto diff = optimal - storm::utility::convertNumber<double>(bestValue);
513 if (foundBestValue) {
514 if (checkUpperParameters) {
515 deltaLower[p] += std::abs(diff);
516 } else {
517 deltaUpper[p] += std::abs(diff);
518 }
519 }
520 }
521 checkUpperParameters = !checkUpperParameters;
522 } while (checkUpperParameters);
523 }
524
525 regionSplitEstimates.clear();
526 useRegionSplitEstimates = false;
527 for (auto const& p : region.getVariables()) {
528 if (this->possibleMonotoneParameters.find(p) != this->possibleMonotoneParameters.end()) {
529 if (deltaLower[p] > deltaUpper[p] && deltaUpper[p] >= 0.0001) {
530 regionSplitEstimates.insert(std::make_pair(p, deltaUpper[p]));
531 useRegionSplitEstimates = true;
532 } else if (deltaLower[p] <= deltaUpper[p] && deltaLower[p] >= 0.0001) {
533 {
534 regionSplitEstimates.insert(std::make_pair(p, deltaLower[p]));
535 useRegionSplitEstimates = true;
536 }
537 }
538 }
539 }
540 // large regionsplitestimate implies that parameter p occurs as p and 1-p at least once
541}
542
543template<typename SparseModelType, typename ConstantType>
545 maybeStates.resize(0);
546 resultsForNonMaybeStates.clear();
547 stepBound = boost::none;
548 instantiationChecker = nullptr;
549 parameterLifter = nullptr;
550 minSchedChoices = boost::none;
551 maxSchedChoices = boost::none;
552 x.clear();
553 lowerResultBound = boost::none;
554 upperResultBound = boost::none;
555 regionSplitEstimationsEnabled = false;
556}
557
558template<typename SparseModelType, typename ConstantType>
560 if (!minSchedChoices) {
561 return boost::none;
562 }
563
564 storm::storage::Scheduler<ConstantType> result(minSchedChoices->size());
565 uint_fast64_t state = 0;
566 for (auto const& schedulerChoice : minSchedChoices.get()) {
567 result.setChoice(schedulerChoice, state);
568 ++state;
569 }
570
571 return result;
572}
573
574template<typename SparseModelType, typename ConstantType>
576 if (!maxSchedChoices) {
577 return boost::none;
578 }
579
580 storm::storage::Scheduler<ConstantType> result(maxSchedChoices->size());
581 uint_fast64_t state = 0;
582 for (auto const& schedulerChoice : maxSchedChoices.get()) {
583 result.setChoice(schedulerChoice, state);
584 ++state;
585 }
586
587 return result;
588}
589
590template<typename SparseModelType, typename ConstantType>
592 return regionSplitEstimationsEnabled && !stepBound;
593}
594
595template<typename SparseModelType, typename ConstantType>
596std::map<typename RegionModelChecker<typename SparseModelType::ValueType>::VariableType, double>
598 STORM_LOG_THROW(isRegionSplitEstimateSupported(), storm::exceptions::InvalidOperationException,
599 "Region split estimation requested but are not enabled (or supported).");
600 return regionSplitEstimates;
601}
602
603template<typename SparseModelType, typename ConstantType>
605 std::shared_ptr<storm::analysis::Order> order, storm::storage::ParameterRegion<ValueType> region) {
606 if (this->orderExtender) {
607 auto res = this->orderExtender->extendOrder(order, region);
608 order = std::get<0>(res);
609 if (std::get<1>(res) != order->getNumberOfStates()) {
610 this->orderExtender.get().setUnknownStates(order, std::get<1>(res), std::get<2>(res));
611 }
612 } else {
613 STORM_LOG_WARN("Extending order for RegionModelChecker not implemented");
614 }
615 return order;
616}
617
618template<typename SparseModelType, typename ConstantType>
620 storm::storage::ParameterRegion<ValueType> const& region, std::shared_ptr<storm::analysis::Order> order,
621 std::shared_ptr<storm::analysis::LocalMonotonicityResult<VariableType>> localMonotonicityResult) {
622 if (this->monotoneIncrParameters && !localMonotonicityResult->isFixedParametersSet()) {
623 for (auto& var : this->monotoneIncrParameters.get()) {
624 localMonotonicityResult->setMonotoneIncreasing(var);
625 }
626 for (auto& var : this->monotoneDecrParameters.get()) {
627 localMonotonicityResult->setMonotoneDecreasing(var);
628 }
629 }
630 auto state = order->getNextDoneState(-1);
631 auto const variablesAtState = parameterLifter->getOccurringVariablesAtState();
632 while (state != order->getNumberOfStates()) {
633 if (localMonotonicityResult->getMonotonicity(state) == nullptr) {
634 auto variables = variablesAtState[state];
635 if (variables.size() == 0 || order->isBottomState(state) || order->isTopState(state)) {
636 localMonotonicityResult->setConstant(state);
637 } else {
638 for (auto const& var : variables) {
639 auto monotonicity = localMonotonicityResult->getMonotonicity(state, var);
640 if (monotonicity == Monotonicity::Unknown || monotonicity == Monotonicity::Not) {
641 monotonicity = monotonicityChecker->checkLocalMonotonicity(order, state, var, region);
642 if (monotonicity == Monotonicity::Unknown || monotonicity == Monotonicity::Not) {
643 // TODO: Skip for now?
644 } else {
645 localMonotonicityResult->setMonotonicity(state, var, monotonicity);
646 }
647 }
648 }
649 }
650 } else {
651 // Do nothing, we already checked this one
652 }
653 state = order->getNextDoneState(state);
654 }
655 auto const statesAtVariable = parameterLifter->getOccuringStatesAtVariable();
656 bool allDone = true;
657 for (auto const& entry : statesAtVariable) {
658 auto states = entry.second;
659 auto var = entry.first;
660 bool done = true;
661 for (auto const& state : states) {
662 done &= order->contains(state) && localMonotonicityResult->getMonotonicity(state, var) != Monotonicity::Unknown;
663 if (!done) {
664 break;
665 }
666 }
667
668 allDone &= done;
669 if (done) {
670 localMonotonicityResult->getGlobalMonotonicityResult()->setDoneForVar(var);
671 }
672 }
673 if (allDone) {
674 localMonotonicityResult->setDone();
675 while (order->existsNextState()) {
676 // Simply add the states we couldn't add sofar between =) and =( as we could find local monotonicity for all parametric states
677 order->add(order->getNextStateNumber().second);
678 }
679 assert(order->getDoneBuilding());
680 }
681}
682
683template<typename SparseModelType, typename ConstantType>
685 std::vector<storm::storage::ParameterRegion<ValueType>>& regionVector,
687 bool splitForExtremum) const {
688 assert(regionVector.size() == 0);
689
690 std::multimap<double, VariableType> sortedOnValues;
691 std::set<VariableType> consideredVariables;
692 if (splitForExtremum) {
693 if (regionSplitEstimationsEnabled && useRegionSplitEstimates) {
694 STORM_LOG_INFO("Splitting based on region split estimates");
695 for (auto& entry : regionSplitEstimates) {
696 assert(!this->isUseMonotonicitySet() ||
697 (!monRes.isMonotone(entry.first) && this->possibleMonotoneParameters.find(entry.first) != this->possibleMonotoneParameters.end()));
698 // sortedOnValues.insert({-(entry.second * storm::utility::convertNumber<double>(region.getDifference(entry.first))*
699 // storm::utility::convertNumber<double>(region.getDifference(entry.first))), entry.first});
700 sortedOnValues.insert({-(entry.second), entry.first});
701 }
702
703 for (auto itr = sortedOnValues.begin(); itr != sortedOnValues.end() && consideredVariables.size() < maxSplitDimensions; ++itr) {
704 consideredVariables.insert(itr->second);
705 }
706 assert(consideredVariables.size() > 0);
707 region.split(region.getCenterPoint(), regionVector, std::move(consideredVariables));
708 } else {
709 STORM_LOG_INFO("Splitting based on sorting");
710
711 auto& sortedOnDifference = region.getVariablesSorted();
712 for (auto itr = sortedOnDifference.begin(); itr != sortedOnDifference.end() && consideredVariables.size() < maxSplitDimensions; ++itr) {
713 if (!this->isUseMonotonicitySet() || !monRes.isMonotone(itr->second)) {
714 consideredVariables.insert(itr->second);
715 }
716 }
717 assert(consideredVariables.size() > 0 || (monRes.isDone() && monRes.isAllMonotonicity()));
718 region.split(region.getCenterPoint(), regionVector, std::move(consideredVariables));
719 }
720 } else {
721 // split for pla
722 if (regionSplitEstimationsEnabled && useRegionSplitEstimates) {
723 STORM_LOG_INFO("Splitting based on region split estimates");
724 ConstantType diff = this->lastValue - (this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
725 for (auto& entry : regionSplitEstimates) {
726 if ((!this->isUseMonotonicitySet() || !monRes.isMonotone(entry.first)) && storm::utility::convertNumber<ConstantType>(entry.second) > diff) {
727 sortedOnValues.insert({-(entry.second * storm::utility::convertNumber<double>(region.getDifference(entry.first)) *
728 storm::utility::convertNumber<double>(region.getDifference(entry.first))),
729 entry.first});
730 }
731 }
732
733 for (auto itr = sortedOnValues.begin(); itr != sortedOnValues.end() && consideredVariables.size() < maxSplitDimensions; ++itr) {
734 consideredVariables.insert(itr->second);
735 }
736 }
737 if (consideredVariables.size() == 0) {
738 auto& sortedOnDifference = region.getVariablesSorted();
739 for (auto itr = sortedOnDifference.begin(); itr != sortedOnDifference.end() && consideredVariables.size() < maxSplitDimensions; ++itr) {
740 consideredVariables.insert(itr->second);
741 }
742 }
743 assert(consideredVariables.size() > 0);
744 region.split(region.getCenterPoint(), regionVector, std::move(consideredVariables));
745 }
746}
747
748template<typename SparseModelType, typename ConstantType>
750 maxSplitDimensions = newValue;
751}
752
753template<typename SparseModelType, typename ConstantType>
755 maxSplitDimensions = std::numeric_limits<uint64_t>::max();
756}
757
760} // namespace modelchecker
761} // namespace storm
bool isAllMonotonicity() const
Returns if all Variables are monotone.
bool isMonotone(VariableType var) const
bool isDone() const
Checks if the result is complete.
FragmentSpecification & setStepBoundedUntilFormulasAllowed(bool newValue)
FragmentSpecification & setTimeBoundedUntilFormulasAllowed(bool newValue)
FragmentSpecification & setCumulativeRewardFormulasAllowed(bool newValue)
FragmentSpecification & setReachabilityRewardFormulasAllowed(bool newValue)
FragmentSpecification & setRewardOperatorsAllowed(bool newValue)
FragmentSpecification & setBoundedUntilFormulasAllowed(bool newValue)
FragmentSpecification & setTimeBoundedCumulativeRewardFormulasAllowed(bool newValue)
FragmentSpecification & setStepBoundedCumulativeRewardFormulasAllowed(bool newValue)
virtual std::unique_ptr< CheckResult > check(Environment const &env, CheckTask< storm::logic::Formula, SolutionType > const &checkTask)
Checks the provided formula.
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:52
bool isRewardModelSet() const
Retrieves whether a reward model was set.
Definition CheckTask.h:190
std::string const & getRewardModel() const
Retrieves the reward model over which to perform the checking (if set).
Definition CheckTask.h:197
FormulaType const & getFormula() const
Retrieves the formula from this task.
Definition CheckTask.h:140
virtual void extendLocalMonotonicityResult(storm::storage::ParameterRegion< ValueType > const &region, std::shared_ptr< storm::analysis::Order > order, std::shared_ptr< storm::analysis::LocalMonotonicityResult< VariableType > > localMonotonicityResult) override
virtual std::shared_ptr< storm::analysis::Order > extendOrder(std::shared_ptr< storm::analysis::Order > order, storm::storage::ParameterRegion< ValueType > region) override
virtual void specifyReachabilityRewardFormula(Environment const &env, CheckTask< storm::logic::EventuallyFormula, ConstantType > const &checkTask) override
virtual storm::modelchecker::SparseInstantiationModelChecker< SparseModelType, ConstantType > & getInstantiationCheckerVIO() override
virtual void specify(Environment const &env, std::shared_ptr< storm::models::ModelBase > parametricModel, CheckTask< storm::logic::Formula, ValueType > const &checkTask, bool generateRegionSplitEstimates=false, bool allowModelSimplification=true) override
virtual bool canHandle(std::shared_ptr< storm::models::ModelBase > parametricModel, CheckTask< storm::logic::Formula, ValueType > const &checkTask) const override
virtual storm::modelchecker::SparseInstantiationModelChecker< SparseModelType, ConstantType > & getInstantiationChecker() override
virtual std::unique_ptr< CheckResult > computeQuantitativeValues(Environment const &env, storm::storage::ParameterRegion< ValueType > const &region, storm::solver::OptimizationDirection const &dirForParameters, std::shared_ptr< storm::analysis::LocalMonotonicityResult< VariableType > > localMonotonicityResult=nullptr) override
virtual void specifyBoundedUntilFormula(const CheckTask< storm::logic::BoundedUntilFormula, ConstantType > &checkTask) override
virtual void splitSmart(storm::storage::ParameterRegion< ValueType > &region, std::vector< storm::storage::ParameterRegion< ValueType > > &regionVector, storm::analysis::MonotonicityResult< VariableType > &monRes, bool splitForExtremum) const override
boost::optional< storm::storage::Scheduler< ConstantType > > getCurrentMinScheduler()
boost::optional< storm::storage::Scheduler< ConstantType > > getCurrentMaxScheduler()
virtual void specifyCumulativeRewardFormula(const CheckTask< storm::logic::CumulativeRewardFormula, ConstantType > &checkTask) override
virtual storm::modelchecker::SparseInstantiationModelChecker< SparseModelType, ConstantType > & getInstantiationCheckerSAT() override
void resetMaxSplitDimensions() override
When splitting, split in every dimension.
void computeRegionSplitEstimates(std::vector< ConstantType > const &quantitativeResult, std::vector< uint_fast64_t > const &schedulerChoices, storm::storage::ParameterRegion< ValueType > const &region, storm::solver::OptimizationDirection const &dirForParameters)
void setMaxSplitDimensions(uint64_t) override
When splitting, split in at most this many dimensions.
virtual void specifyUntilFormula(Environment const &env, CheckTask< storm::logic::UntilFormula, ConstantType > const &checkTask) override
void specify_internal(Environment const &env, std::shared_ptr< SparseModelType > parametricModel, CheckTask< storm::logic::Formula, ValueType > const &checkTask, bool generateRegionSplitEstimates, bool skipModelSimplification)
virtual bool isRegionSplitEstimateSupported() const override
Returns true if region split estimation (a) was enabled when model and check task have been specified...
virtual std::map< VariableType, double > getRegionSplitEstimate() const override
Returns an estimate of the benefit of splitting the last checked region with respect to each paramete...
Class to efficiently check a formula on a parametric model with different parameter instantiations.
void specifyFormula(CheckTask< storm::logic::Formula, typename SparseModelType::ValueType > const &checkTask)
virtual bool canHandle(CheckTask< storm::logic::Formula, SolutionType > const &checkTask) const override
Determines whether the model checker can handle the given verification task.
ValueType computeUpperBound()
Computes an upper bound on the expected rewards.
std::vector< ValueType > computeUpperBounds()
Computes upper bounds on the expected rewards.
std::unique_ptr< Multiplier< ValueType > > create(Environment const &env, storm::storage::SparseMatrix< ValueType > const &matrix)
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
void complement()
Negates all bits in the bit vector.
void set(uint_fast64_t index, bool value=true)
Sets the given truth value at the given index.
std::set< VariableType > const & getVariables() const
Valuation getCenterPoint() const
Returns the center point of this region.
CoefficientType getDifference(const std::string varName) const
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...
std::multimap< CoefficientType, VariableType > const & getVariablesSorted() const
This class defines which action is chosen in a particular state of a non-deterministic model.
Definition Scheduler.h:18
void setChoice(SchedulerChoice< ValueType > const &choice, uint_fast64_t modelState, uint_fast64_t memoryState=0)
Sets the choice defined by the scheduler for the given state.
Definition Scheduler.cpp:37
This class performs different steps to simplify the given (parametric) model.
#define STORM_LOG_INFO(message)
Definition logging.h:29
#define STORM_LOG_WARN(message)
Definition logging.h:30
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
FragmentSpecification reachability()
bool constexpr maximize(OptimizationDirection d)
bool constexpr minimize(OptimizationDirection d)
std::pair< storm::storage::BitVector, storm::storage::BitVector > performProb01(storm::models::sparse::DeterministicModel< T > const &model, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Computes the sets of states that have probability 0 or 1, respectively, of satisfying phi until psi i...
Definition graph.cpp:400
storm::storage::BitVector performProbGreater0(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps)
Performs a backward depth-first search trough the underlying graph structure of the given model to de...
Definition graph.cpp:322
storm::storage::BitVector performProb1(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &, storm::storage::BitVector const &psiStates, storm::storage::BitVector const &statesWithProbabilityGreater0)
Computes the set of states of the given model for which all paths lead to the given set of target sta...
Definition graph.cpp:383
void setVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< T > const &values)
Sets the provided values at the provided positions in the given vector.
Definition vector.h:83
LabParser.cpp.
Definition cli.cpp:18