24template<
typename ValueType,
typename ConstantType>
28 this->matrix = model->getTransitionMatrix();
29 this->numberOfStates = this->model->getNumberOfStates();
30 this->formula = formula;
31 this->assumptionMaker = std::make_unique<analysis::AssumptionMaker<ValueType, ConstantType>>(matrix);
34template<
typename ValueType,
typename ConstantType>
38 this->matrix = matrix;
39 this->model =
nullptr;
41 this->numberOfStates = matrix.getColumnCount();
43 this->bottomTopOrder = computeInitialOrder(topStates, bottomStates, matrix,
true);
45 this->assumptionMaker = std::make_unique<analysis::AssumptionMaker<ValueType, ConstantType>>(matrix);
48template<
typename ValueType,
typename ConstantType>
49std::shared_ptr<Order> OrderExtender<ValueType, ConstantType>::computeInitialOrder(
storm::storage::BitVector const& topStates,
52 bool addStatesWithDirectBoundaryTransition) {
56 std::vector<uint64_t> firstStates;
58 for (
auto state : topStates) {
59 firstStates.push_back(state);
60 subStates.set(state,
false);
62 for (
auto state : bottomStates) {
63 firstStates.push_back(state);
64 subStates.set(state,
false);
73 auto order = std::make_shared<Order>(topStates, bottomStates, numberOfStates, std::move(decomposition), std::move(statesSorted));
76 for (uint_fast64_t state = 0; state < numberOfStates; ++state) {
77 auto const& row = matrix.
getRow(state);
78 stateMap[state] = std::vector<uint_fast64_t>();
79 std::set<VariableType> occurringVariables;
81 for (
auto& entry : matrix.
getRow(state)) {
83 if (state != entry.getColumn() || row.getNumberOfEntries() == 1) {
84 if (addStatesWithDirectBoundaryTransition && !subStates[entry.getColumn()] && !order->contains(state)) {
87 stateMap[state].push_back(entry.getColumn());
91 if (occurringVariables.empty()) {
92 nonParametricStates.insert(state);
95 for (
auto& var : occurringVariables) {
96 occuringStatesAtVariable[var].push_back(state);
98 occuringVariablesAtState.push_back(std::move(occurringVariables));
104template<
typename ValueType,
typename ConstantType>
105std::shared_ptr<Order> OrderExtender<ValueType, ConstantType>::getBottomTopOrder() {
106 if (bottomTopOrder ==
nullptr) {
107 STORM_LOG_ASSERT(model !=
nullptr,
"Cannot lazily build the bottom-top order without a model.");
109 "Creating order not supported for non-square matrix");
110 modelchecker::SparsePropositionalModelChecker<models::sparse::Model<ValueType>> propositionalChecker(*model);
111 storage::BitVector phiStates;
112 storage::BitVector psiStates;
113 STORM_LOG_ASSERT(formula->isProbabilityOperatorFormula(),
"Expected a probability operator formula.");
114 if (formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) {
115 phiStates = propositionalChecker.check(formula->asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())
116 ->template asExplicitQualitativeCheckResult<ValueType>()
117 .getTruthValuesVector();
118 psiStates = propositionalChecker.check(formula->asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())
119 ->template asExplicitQualitativeCheckResult<ValueType>()
120 .getTruthValuesVector();
122 STORM_LOG_ASSERT(formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula(),
"Expected an eventually formula.");
123 phiStates = storage::BitVector(numberOfStates,
true);
124 psiStates = propositionalChecker.check(formula->asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())
125 ->template asExplicitQualitativeCheckResult<ValueType>()
126 .getTruthValuesVector();
129 std::pair<storage::BitVector, storage::BitVector> statesWithProbability01 =
131 storage::BitVector topStates = statesWithProbability01.second;
132 storage::BitVector bottomStates = statesWithProbability01.first;
134 STORM_LOG_THROW(topStates.begin() != topStates.end(), exceptions::NotSupportedException,
"Formula yields to no 1 states");
135 STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), exceptions::NotSupportedException,
"Formula yields to no zero states");
139 bottomTopOrder = computeInitialOrder(topStates, bottomStates, this->model->getTransitionMatrix(),
false);
142 if (minValuesInit && maxValuesInit) {
143 auto& ctx = context(bottomTopOrder);
144 ctx.continueExtending =
true;
146 ctx.minValues = std::move(minValuesInit.get());
147 ctx.maxValues = std::move(maxValuesInit.get());
149 minValuesInit = boost::none;
150 maxValuesInit = boost::none;
152 return bottomTopOrder;
155template<
typename ValueType,
typename ConstantType>
156typename OrderExtender<ValueType, ConstantType>::Context& OrderExtender<ValueType, ConstantType>::context(std::shared_ptr<Order>
const& order) {
157 auto result = contexts.try_emplace(order);
159 result.first->second.unknownStates = {numberOfStates, numberOfStates};
162 if (contexts.size() >= nextContextPruneSize) {
163 for (
auto it = contexts.begin(); it != contexts.end();) {
164 if (it->first.expired()) {
165 it = contexts.erase(it);
170 nextContextPruneSize = std::max<std::size_t>(64, contexts.size() * 2);
173 return result.first->second;
176template<
typename ValueType,
typename ConstantType>
177typename OrderExtender<ValueType, ConstantType>::Context
const& OrderExtender<ValueType, ConstantType>::contextAt(std::shared_ptr<Order>
const& order)
const {
178 auto it = contexts.find(order);
183template<
typename ValueType,
typename ConstantType>
186 return this->
extendOrder(
nullptr, region, monRes, std::nullopt);
189template<
typename ValueType,
typename ConstantType>
190void OrderExtender<ValueType, ConstantType>::handleAssumption(std::shared_ptr<Order> order,
Assumption const& assumption)
const {
191 uint_fast64_t val1 = assumption.
state1;
192 uint_fast64_t val2 = assumption.
state2;
200 if (n1 !=
nullptr && n2 !=
nullptr) {
201 order->mergeNodes(n1, n2);
202 }
else if (n1 !=
nullptr) {
203 order->addToNode(val2, n1);
204 }
else if (n2 !=
nullptr) {
205 order->addToNode(val1, n2);
208 order->addToNode(val2, order->getNode(val1));
211 if (n1 !=
nullptr && n2 !=
nullptr) {
212 order->addRelationNodes(n1, n2);
213 }
else if (n1 !=
nullptr) {
214 order->addBetween(val2, n1, order->getBottom());
215 }
else if (n2 !=
nullptr) {
216 order->addBetween(val1, order->getTop(), n2);
219 order->addBetween(val2, order->getNode(val1), order->getBottom());
224template<
typename ValueType,
typename ConstantType>
227 std::optional<Assumption> assumption) {
228 this->region = region;
229 if (order ==
nullptr) {
230 order = getBottomTopOrder();
231 auto& initialContext = context(order);
232 if (initialContext.usePLA) {
233 auto& min = initialContext.minValues;
234 auto& max = initialContext.maxValues;
236 auto& statesSorted = order->getStatesSorted();
237 auto itr = statesSorted.begin();
238 while (itr != statesSorted.end()) {
240 auto& successors = stateMap[state];
242 for (uint_fast64_t i = 0; i < successors.size(); ++i) {
243 auto state1 = successors[i];
244 for (uint_fast64_t j = i + 1; j < successors.size(); ++j) {
245 auto state2 = successors[j];
246 if (min[state1] > max[state2]) {
247 if (!order->contains(state1)) {
250 if (!order->contains(state2)) {
253 order->addRelation(state1, state2,
false);
254 }
else if (min[state2] > max[state1]) {
255 if (!order->contains(state1)) {
258 if (!order->contains(state2)) {
261 order->addRelation(state2, state1,
false);
262 }
else if (min[state1] == max[state2] && max[state1] == min[state2]) {
263 if (!order->contains(state1) && !order->contains(state2)) {
265 order->addToNode(state2, order->getNode(state1));
266 }
else if (!order->contains(state1)) {
267 order->addToNode(state1, order->getNode(state2));
268 }
else if (!order->contains(state2)) {
269 order->addToNode(state2, order->getNode(state1));
270 }
else if (!order->merge(state1, state2)) {
274 return std::make_tuple(order, numberOfStates, numberOfStates);
282 STORM_LOG_INFO(
"All successors of state " << state <<
" sorted based on min max values");
287 initialContext.continueExtending =
true;
289 auto& ctx = context(order);
290 if (ctx.continueExtending || assumption.has_value()) {
293 auto res = ctx.unknownStates;
294 ctx.continueExtending =
false;
295 return {order, res.first, res.second};
299template<
typename ValueType,
typename ConstantType>
302 if (assumption.has_value()) {
304 handleAssumption(order, *assumption);
305 if (order->isInvalid()) {
308 return std::make_tuple(order, numberOfStates, numberOfStates);
312 auto currentStateMode = getNextState(order, numberOfStates,
false);
313 while (currentStateMode.first != numberOfStates) {
314 STORM_LOG_ASSERT(currentStateMode.first < numberOfStates,
"Expected a valid state, not the sentinel value.");
315 auto& currentState = currentStateMode.first;
316 auto& successors = stateMap[currentState];
317 std::pair<uint_fast64_t, uint_fast64_t> result = {numberOfStates, numberOfStates};
319 if (successors.size() == 1) {
320 STORM_LOG_ASSERT(order->contains(successors[0]),
"The single successor of a state must already be in the order.");
321 handleOneSuccessor(order, currentState, successors[0]);
322 }
else if (!successors.empty()) {
323 if (order->isOnlyBottomTopOrder()) {
324 order->add(currentState);
325 if (!order->isTrivial(currentState)) {
327 result = extendByForwardReasoning(order, currentState, successors, assumption.has_value());
329 result = {numberOfStates, numberOfStates};
332 result = extendNormal(order, currentState, successors, assumption.has_value());
336 if (order->isInvalid()) {
340 return std::make_tuple(order, numberOfStates, numberOfStates);
343 if (result.first == numberOfStates) {
345 STORM_LOG_ASSERT(result.second == numberOfStates,
"Expected both entries of result to be the sentinel value.");
346 STORM_LOG_ASSERT(order->sortStates(&successors).size() == successors.size(),
"Expected all successors to be sortable at this point.");
347 STORM_LOG_ASSERT(order->contains(currentState) && order->getNode(currentState) !=
nullptr,
348 "The current state should have been placed in the order.");
350 if (monRes !=
nullptr) {
351 for (
auto& param : occuringVariablesAtState[currentState]) {
352 checkParOnStateMonRes(currentState, order, param, monRes);
356 currentStateMode = getNextState(order, currentState,
true);
358 STORM_LOG_ASSERT(result.first < numberOfStates,
"Expected a valid state, not the sentinel value.");
359 STORM_LOG_ASSERT(result.second < numberOfStates,
"Expected a valid state, not the sentinel value.");
363 if (currentStateMode.second && extendByAssumption(order, result.first, result.second)) {
364 if (order->isInvalid()) {
365 return std::make_tuple(order, numberOfStates, numberOfStates);
370 if (nonParametricStates.find(currentState) != nonParametricStates.end()) {
371 if (!order->contains(currentState)) {
373 order->add(currentState);
375 currentStateMode = getNextState(order, currentState,
true);
378 if (!currentStateMode.second) {
380 currentStateMode = getNextState(order, currentState,
false);
385 order->addStateSorted(currentState);
386 context(order).continueExtending =
false;
387 return {order, result.first, result.second};
393 STORM_LOG_ASSERT(order->getDoneBuilding(),
"Expected the order to be fully built at this point.");
394 if (monRes !=
nullptr) {
398 return std::make_tuple(order, numberOfStates, numberOfStates);
401template<
typename ValueType,
typename ConstantType>
402std::pair<uint_fast64_t, uint_fast64_t> OrderExtender<ValueType, ConstantType>::extendNormal(std::shared_ptr<Order> order, uint_fast64_t currentState,
403 const std::vector<uint_fast64_t>& successors,
bool allowMerge) {
405 if (cyclic && !order->isTrivial(currentState) && order->contains(currentState)) {
407 return extendByForwardReasoning(order, currentState, successors, allowMerge);
409 STORM_LOG_ASSERT(order->isTrivial(currentState) || !order->contains(currentState),
410 "A non-trivial (SCC) state that is already in the order should use forward reasoning, not backward reasoning.");
412 return extendByBackwardReasoning(order, currentState, successors, allowMerge);
416template<
typename ValueType,
typename ConstantType>
417void OrderExtender<ValueType, ConstantType>::handleOneSuccessor(std::shared_ptr<Order> order, uint_fast64_t currentState, uint_fast64_t successor) {
418 STORM_LOG_ASSERT(order->contains(successor),
"The successor must already be in the order.");
419 if (currentState != successor) {
420 if (order->contains(currentState)) {
421 order->merge(currentState, successor);
423 order->addToNode(currentState, order->getNode(successor));
428template<
typename ValueType,
typename ConstantType>
429std::pair<uint_fast64_t, uint_fast64_t> OrderExtender<ValueType, ConstantType>::extendByBackwardReasoning(std::shared_ptr<Order> order,
430 uint_fast64_t currentState,
431 std::vector<uint_fast64_t>
const& successors,
433 STORM_LOG_ASSERT(!order->isOnlyBottomTopOrder(),
"Backward reasoning requires the order to have grown beyond just top and bottom.");
434 STORM_LOG_ASSERT(successors.size() > 1,
"Backward reasoning is only needed for states with more than one successor.");
436 auto& ctx = context(order);
437 bool pla = ctx.usePLA;
438 std::vector<uint_fast64_t> sortedSuccs;
440 if (pla && ctx.continueExtending) {
441 for (
auto& state1 : successors) {
442 if (sortedSuccs.size() == 0) {
443 sortedSuccs.push_back(state1);
446 for (
auto itr = sortedSuccs.begin(); itr != sortedSuccs.end(); ++itr) {
448 auto compareRes = order->compareFast(state1, state2);
450 compareRes = addStatesBasedOnMinMax(order, state1, state2);
454 compareRes = order->compare(state1, state2);
458 sortedSuccs.insert(itr, state1);
462 ctx.continueExtending =
false;
463 return {state1, state2};
467 sortedSuccs.push_back(state1);
472 auto temp = order->sortStatesUnorderedPair(&successors);
473 if (temp.first.first != numberOfStates) {
476 sortedSuccs = std::move(temp.second);
480 if (order->compare(sortedSuccs[0], sortedSuccs[sortedSuccs.size() - 1]) ==
Order::SAME) {
481 if (!order->contains(currentState)) {
482 order->addToNode(currentState, order->getNode(sortedSuccs[0]));
484 order->merge(currentState, sortedSuccs[0]);
487 if (!order->contains(sortedSuccs[0])) {
488 STORM_LOG_ASSERT(order->isBottomState(sortedSuccs[sortedSuccs.size() - 1]),
"Expected the other successor to be a bottom state.");
489 STORM_LOG_ASSERT(sortedSuccs.size() == 2,
"Expected exactly two successors in this case.");
490 order->addAbove(sortedSuccs[0], order->getBottom());
492 if (!order->contains(sortedSuccs[sortedSuccs.size() - 1])) {
493 STORM_LOG_ASSERT(order->isTopState(sortedSuccs[0]),
"Expected the other successor to be a top state.");
494 STORM_LOG_ASSERT(sortedSuccs.size() == 2,
"Expected exactly two successors in this case.");
495 order->addBelow(sortedSuccs[sortedSuccs.size() - 1], order->getTop());
498 if (!order->contains(currentState)) {
499 order->addBetween(currentState, sortedSuccs[0], sortedSuccs[sortedSuccs.size() - 1]);
501 order->addRelation(sortedSuccs[0], currentState, allowMerge);
502 order->addRelation(currentState, sortedSuccs[sortedSuccs.size() - 1], allowMerge);
506 order->compare(order->getNode(currentState), order->getTop()) ==
Order::BELOW,
507 "The current state should have ended up strictly between top and bottom in the order.");
508 return {numberOfStates, numberOfStates};
511template<
typename ValueType,
typename ConstantType>
512std::pair<uint_fast64_t, uint_fast64_t> OrderExtender<ValueType, ConstantType>::extendByForwardReasoning(std::shared_ptr<Order> order,
513 uint_fast64_t currentState,
514 std::vector<uint_fast64_t>
const& successors,
516 STORM_LOG_ASSERT(successors.size() > 1,
"Forward reasoning is only needed for states with more than one successor.");
517 STORM_LOG_ASSERT(order->contains(currentState),
"The current state must already be in the order before doing forward reasoning on it.");
518 STORM_LOG_ASSERT(cyclic,
"Forward reasoning is only applicable to cyclic pMCs.");
520 std::vector<uint_fast64_t> statesSorted;
521 statesSorted.push_back(currentState);
522 bool pla = context(order).usePLA;
524 bool oneUnknown =
false;
525 bool unknown =
false;
526 uint_fast64_t s1 = numberOfStates;
527 uint_fast64_t s2 = numberOfStates;
528 for (
auto& state : successors) {
531 for (
auto itr = statesSorted.begin(); itr != statesSorted.end(); ++itr) {
532 auto compareRes = order->compareFast(state, (*itr));
534 compareRes = addStatesBasedOnMinMax(order, state, (*itr));
537 compareRes = order->compare(state, *itr);
542 order->addStateToHandle(state);
546 statesSorted.insert(itr, state);
561 if (!(unknown && oneUnknown) && !added) {
563 statesSorted.push_back(state);
565 if (unknown && oneUnknown) {
569 if (!unknown && oneUnknown) {
570 STORM_LOG_ASSERT(statesSorted.size() == successors.size(),
"Expected all but the single unresolved successor to have been sorted.");
574 if (s1 == numberOfStates) {
575 STORM_LOG_ASSERT(statesSorted.size() == successors.size() + 1,
"Expected all successors (plus the current state) to have been sorted.");
577 }
else if (s2 == numberOfStates) {
578 if (!order->contains(s1)) {
582 if (statesSorted[0] == currentState) {
583 order->addRelation(s1, statesSorted[0], allowMerge);
587 "Expected s1 to end up above (or, if merged, equal to) statesSorted[0].");
588 order->addRelation(s1, statesSorted[statesSorted.size() - 1], allowMerge);
590 (allowMerge && (order->compare(s1, statesSorted[statesSorted.size() - 1]) ==
Order::SAME)),
591 "Expected s1 to end up above (or, if merged, equal to) the lowest sorted successor.");
592 order->addStateToHandle(s1);
593 }
else if (statesSorted[statesSorted.size() - 1] == currentState) {
594 order->addRelation(statesSorted[0], s1, allowMerge);
598 "Expected s1 to end up below (or, if merged, equal to) statesSorted[0].");
599 order->addRelation(statesSorted[statesSorted.size() - 1], s1, allowMerge);
601 (allowMerge && (order->compare(s1, statesSorted[statesSorted.size() - 1]) ==
Order::SAME)),
602 "Expected s1 to end up below (or, if merged, equal to) the highest sorted successor.");
603 order->addStateToHandle(s1);
605 bool continueSearch =
true;
606 for (
auto& entry : matrix.
getRow(currentState)) {
607 if (entry.getColumn() == s1) {
608 if (entry.getValue().isConstant()) {
609 continueSearch =
false;
613 if (continueSearch) {
614 for (
auto& i : statesSorted) {
625 order->compare(order->getNode(currentState), order->getTop()) ==
Order::BELOW,
626 "The current state should have ended up strictly between top and bottom in the order.");
627 return {numberOfStates, numberOfStates};
630template<
typename ValueType,
typename ConstantType>
631bool OrderExtender<ValueType, ConstantType>::extendByAssumption(std::shared_ptr<Order> order, uint_fast64_t state1, uint_fast64_t state2) {
632 auto& ctx = context(order);
634 STORM_LOG_ASSERT(!ctx.usePLA || (ctx.minValues.size() == numberOfStates && ctx.maxValues.size() == numberOfStates),
635 "The PLA path requires both bound vectors to be available.");
636 auto assumptions = ctx.usePLA ? assumptionMaker->createAndCheckAssumptions(state1, state2, order, region, ctx.minValues, ctx.maxValues)
637 : assumptionMaker->createAndCheckAssumptions(state1, state2, order, region);
639 handleAssumption(order, assumptions.begin()->first);
646template<
typename ValueType,
typename ConstantType>
647Order::NodeComparison OrderExtender<ValueType, ConstantType>::addStatesBasedOnMinMax(std::shared_ptr<Order> order, uint_fast64_t state1,
648 uint_fast64_t state2)
const {
650 auto const& ctx = contextAt(order);
651 std::vector<ConstantType>
const& mins = ctx.minValues;
652 std::vector<ConstantType>
const& maxs = ctx.maxValues;
653 if (mins[state1] == maxs[state1] && mins[state2] == maxs[state2] && mins[state1] == mins[state2]) {
654 if (order->contains(state1)) {
655 if (order->contains(state2)) {
656 if (!order->merge(state1, state2)) {
663 order->addToNode(state2, order->getNode(state1));
667 }
else if (mins[state1] > maxs[state2]) {
669 if (!order->contains(state1)) {
672 if (!order->contains(state2)) {
675 STORM_LOG_ASSERT(order->compare(state1, state2) !=
Order::BELOW,
"min/max values say state1 is above state2, contradicting the order.");
676 STORM_LOG_ASSERT(order->compare(state1, state2) !=
Order::SAME,
"min/max values say state1 is strictly above state2, contradicting the order.");
677 order->addRelation(state1, state2);
680 }
else if (mins[state2] > maxs[state1]) {
682 if (!order->contains(state1)) {
685 if (!order->contains(state2)) {
688 STORM_LOG_ASSERT(order->compare(state2, state1) !=
Order::BELOW,
"min/max values say state2 is above state1, contradicting the order.");
689 STORM_LOG_ASSERT(order->compare(state2, state1) !=
Order::SAME,
"min/max values say state2 is strictly above state1, contradicting the order.");
690 order->addRelation(state2, state1);
698template<
typename ValueType,
typename ConstantType>
700 if (model !=
nullptr) {
703 std::unique_ptr<modelchecker::CheckResult> checkResult;
704 boost::optional<modelchecker::CheckTask<logic::Formula, ValueType>> checkTask;
705 if (this->formula->hasQuantitativeResult()) {
710 std::make_shared<storm::logic::ProbabilityOperatorFormula>(formula->asProbabilityOperatorFormula().getSubformula().asSharedPointer(), opInfo);
713 STORM_LOG_THROW(plaModelChecker.
canHandle(model, checkTask.get()), exceptions::NotSupportedException,
"Cannot handle this formula");
714 bool const allowModelSimplification =
false;
715 plaModelChecker.
specify(env, model, checkTask.get(), std::nullopt,
nullptr, allowModelSimplification);
719 plaModelChecker.
check(env, annotatedRegion, solver::OptimizationDirection::Minimize)->template asExplicitQuantitativeCheckResult<ConstantType>();
721 plaModelChecker.
check(env, annotatedRegion, solver::OptimizationDirection::Maximize)->template asExplicitQuantitativeCheckResult<ConstantType>();
724 STORM_LOG_ASSERT(minValuesInit->size() == numberOfStates,
"Expected one lower bound per state.");
725 STORM_LOG_ASSERT(maxValuesInit->size() == numberOfStates,
"Expected one upper bound per state.");
729template<
typename ValueType,
typename ConstantType>
731 std::vector<ConstantType>&& maxValues) {
732 STORM_LOG_ASSERT(minValues.size() == numberOfStates,
"Expected one lower bound per state.");
733 STORM_LOG_ASSERT(maxValues.size() == numberOfStates,
"Expected one upper bound per state.");
734 auto& ctx = context(order);
736 if (ctx.unknownStates.first != numberOfStates) {
737 ctx.continueExtending = minValues[ctx.unknownStates.first] >= maxValues[ctx.unknownStates.second] ||
738 minValues[ctx.unknownStates.second] >= maxValues[ctx.unknownStates.first];
740 ctx.continueExtending =
true;
742 ctx.minValues = std::move(minValues);
743 ctx.maxValues = std::move(maxValues);
746template<
typename ValueType,
typename ConstantType>
748 STORM_LOG_ASSERT(minValues.size() == numberOfStates,
"Expected one lower bound per state.");
749 auto& ctx = context(order);
752 ctx.usePLA = !ctx.maxValues.empty();
753 if (ctx.maxValues.size() == 0) {
754 ctx.continueExtending =
false;
755 }
else if (ctx.unknownStates.first != numberOfStates) {
756 ctx.continueExtending = minValues[ctx.unknownStates.first] >= ctx.maxValues[ctx.unknownStates.second] ||
757 minValues[ctx.unknownStates.second] >= ctx.maxValues[ctx.unknownStates.first];
759 ctx.continueExtending =
true;
761 ctx.minValues = std::move(minValues);
764template<
typename ValueType,
typename ConstantType>
766 STORM_LOG_ASSERT(maxValues.size() == numberOfStates,
"Expected one upper bound per state.");
767 auto& ctx = context(order);
768 ctx.usePLA = !ctx.minValues.empty();
769 if (ctx.minValues.size() == 0) {
770 ctx.continueExtending =
false;
771 }
else if (ctx.unknownStates.first != numberOfStates) {
772 ctx.continueExtending = ctx.minValues[ctx.unknownStates.first] >= maxValues[ctx.unknownStates.second] ||
773 ctx.minValues[ctx.unknownStates.second] >= maxValues[ctx.unknownStates.first];
775 ctx.continueExtending =
true;
777 ctx.maxValues = std::move(maxValues);
779template<
typename ValueType,
typename ConstantType>
781 STORM_LOG_ASSERT(minValues.size() == numberOfStates,
"Expected one lower bound per state.");
782 this->minValuesInit = std::move(minValues);
785template<
typename ValueType,
typename ConstantType>
787 STORM_LOG_ASSERT(maxValues.size() == numberOfStates,
"Expected one upper bound per state.");
788 this->maxValuesInit = std::move(maxValues);
791template<
typename ValueType,
typename ConstantType>
795 auto mon = monotonicityChecker.checkLocalMonotonicity(order, s, param, region);
796 monResult->updateMonotonicityResult(param, mon);
799template<
typename ValueType,
typename ConstantType>
801 STORM_LOG_ASSERT(state1 != numberOfStates && state2 != numberOfStates,
"Expected two actual states, not the sentinel value.");
802 context(order).unknownStates = {state1, state2};
805template<
typename ValueType,
typename ConstantType>
807 auto it = contexts.find(order);
808 if (it != contexts.end()) {
809 return it->second.unknownStates;
811 return {numberOfStates, numberOfStates};
814template<
typename ValueType,
typename ConstantType>
816 STORM_LOG_ASSERT(contexts.find(orderCopy) == contexts.end(),
"The copy must not already have a context set.");
817 contexts[orderCopy] = contextAt(orderOriginal);
820template<
typename ValueType,
typename ConstantType>
821std::pair<uint_fast64_t, bool> OrderExtender<ValueType, ConstantType>::getNextState(std::shared_ptr<Order> order, uint_fast64_t currentState,
bool done) {
822 if (done && currentState != numberOfStates) {
823 order->setDoneState(currentState);
825 if (cyclic && order->existsStateToHandle()) {
826 return order->getStateToHandle();
828 if (currentState == numberOfStates) {
829 return order->getNextStateNumber();
831 if (currentState != numberOfStates) {
832 return order->getNextStateNumber();
834 return {numberOfStates,
true};
837template<
typename ValueType,
typename ConstantType>
839 STORM_LOG_ASSERT(contexts.find(order) != contexts.end(),
"Expected a context to be set for this order.");
840 STORM_LOG_ASSERT(!order->getDoneBuilding(),
"Asking for hope on an order that is already fully built is meaningless.");
842 return context(order).continueExtending;
844template<
typename ValueType,
typename ConstantType>
846 return monotonicityChecker;
848template<
typename ValueType,
typename ConstantType>
849const std::vector<std::set<typename OrderExtender<ValueType, ConstantType>::VariableType>>&
851 return occuringVariablesAtState;
void initializeMinMaxValues(Environment const &env, storage::ParameterRegion< ValueType > region)
void setMaxValuesInit(std::vector< ConstantType > &&minValues)
std::vector< std::set< VariableType > > const & getVariablesOccuringAtState()
std::pair< uint_fast64_t, uint_fast64_t > getUnknownStates(std::shared_ptr< Order > order) const
std::tuple< std::shared_ptr< Order >, uint_fast64_t, uint_fast64_t > extendOrder(std::shared_ptr< Order > order, storm::storage::ParameterRegion< ValueType > region, std::shared_ptr< MonotonicityResult< VariableType > > monRes=nullptr, std::optional< Assumption > assumption=std::nullopt)
Extends the order for the given region.
void setMaxValues(std::shared_ptr< Order > order, std::vector< ConstantType > &&maxValues)
MonotonicityChecker< ValueType > & getMonotoncityChecker()
void setMinValues(std::shared_ptr< Order > order, std::vector< ConstantType > &&minValues)
void setMinValuesInit(std::vector< ConstantType > &&minValues)
void setUnknownStates(std::shared_ptr< Order > order, uint_fast64_t state1, uint_fast64_t state2)
OrderExtender(std::shared_ptr< models::sparse::Model< ValueType > > model, std::shared_ptr< logic::Formula const > formula)
Constructs a new OrderExtender.
void copyContext(std::shared_ptr< Order > orderOriginal, std::shared_ptr< Order > orderCopy)
utility::parametric::VariableType< ValueType >::type VariableType
std::tuple< std::shared_ptr< Order >, uint_fast64_t, uint_fast64_t > toOrder(storage::ParameterRegion< ValueType > region, std::shared_ptr< MonotonicityResult< VariableType > > monRes=nullptr)
Creates an order based on the given formula.
void setMinMaxValues(std::shared_ptr< Order > order, std::vector< ConstantType > &&minValues, std::vector< ConstantType > &&maxValues)
void checkParOnStateMonRes(uint_fast64_t s, std::shared_ptr< Order > order, typename OrderExtender< ValueType, ConstantType >::VariableType param, std::shared_ptr< MonotonicityResult< VariableType > > monResult)
bool isHope(std::shared_ptr< Order > order)
NodeComparison
Constants for comparison of nodes/states.
A quantitative check result over the states of a sparse model.
std::vector< ValueType > getFiniteValueVector() const
virtual bool canHandle(std::shared_ptr< storm::models::ModelBase > parametricModel, CheckTask< storm::logic::Formula, ParametricType > const &checkTask) const override
virtual void specify(Environment const &env, std::shared_ptr< storm::models::ModelBase > parametricModel, CheckTask< storm::logic::Formula, ParametricType > const &checkTask, std::optional< RegionSplitEstimateKind > generateRegionSplitEstimates=std::nullopt, std::shared_ptr< MonotonicityBackend< ParametricType > > monotonicityBackend={}, bool allowModelSimplifications=true, storm::pars::analysis::GraphPreservationStatus graphPreservationStatus=storm::pars::analysis::GraphPreservationStatus::GraphPreserving) override
std::unique_ptr< CheckResult > check(Environment const &env, AnnotatedRegion< ParametricType > ®ion, storm::solver::OptimizationDirection const &dirForParameters)
Checks the specified formula on the given region by applying parameter lifting (Parameter choices are...
Base class for all sparse models.
A bit vector that is internally represented as a vector of 64-bit values.
size_t size() const
Retrieves the number of bits this bit vector can store.
A class that holds a possibly non-square matrix in the compressed row storage format.
const_rows getRow(index_type row) const
Returns an object representing the given row.
index_type getColumnCount() const
Returns the number of columns of the matrix.
storm::storage::SparseMatrix< value_type > transpose(bool joinGroups=false, bool keepZeros=false) const
Transposes the matrix.
index_type getRowCount() const
Returns the number of rows of the matrix.
This class represents the decomposition of a graph-like structure into its strongly connected compone...
#define STORM_LOG_INFO(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
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...
std::vector< uint_fast64_t > getTopologicalSort(storm::storage::SparseMatrix< T > const &matrix, std::vector< uint64_t > const &firstStates)
Performs a topological sort of the states of the system according to the given transitions.
bool hasCycle(storm::storage::SparseMatrix< T > const &transitionMatrix, boost::optional< storm::storage::BitVector > const &subsystem)
Returns true if the graph represented by the given matrix has a cycle.
void gatherOccurringVariables(FunctionType const &function, std::set< typename VariableType< FunctionType >::type > &variableSet)
Add all variables that occur in the given function to the the given set.
A candidate relation between two states of a reachability order: either state1 > state2 (Greater) or ...
AssumptionRelation relation
Nodes of the Reachability Order.
StronglyConnectedComponentDecompositionOptions & forceTopologicalSort(bool value=true)
Enforces that the returned SCCs are sorted in a topological order.