Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
OrderExtender.cpp
Go to the documentation of this file.
1#include "OrderExtender.h"
2#include <vector>
3
11
17
19
20namespace storm {
21namespace analysis {
22
23template<typename ValueType, typename ConstantType>
24OrderExtender<ValueType, ConstantType>::OrderExtender(std::shared_ptr<models::sparse::Model<ValueType>> model, std::shared_ptr<logic::Formula const> formula)
25 : monotonicityChecker(MonotonicityChecker<ValueType>(model->getTransitionMatrix())) {
26 this->model = model;
27 this->matrix = model->getTransitionMatrix();
28 this->numberOfStates = this->model->getNumberOfStates();
29 this->formula = formula;
30 this->assumptionMaker = new analysis::AssumptionMaker<ValueType, ConstantType>(matrix);
31}
32
33template<typename ValueType, typename ConstantType>
36 : monotonicityChecker(MonotonicityChecker<ValueType>(matrix)) {
37 this->matrix = matrix;
38 this->model = nullptr;
39 this->monotonicityChecker = MonotonicityChecker<ValueType>(matrix);
40
42 options.forceTopologicalSort();
43
44 this->numberOfStates = matrix.getColumnCount();
45 std::vector<uint64_t> firstStates;
46
47 storm::storage::BitVector subStates(topStates.size(), true);
48 for (uint64_t state : topStates) {
49 firstStates.push_back(state);
50 subStates.set(state, false);
51 }
52 for (uint64_t state : bottomStates) {
53 firstStates.push_back(state);
54 subStates.set(state, false);
55 }
56 cyclic = storm::utility::graph::hasCycle(matrix, subStates);
58 if (cyclic) {
60 }
61
62 auto statesSorted = storm::utility::graph::getTopologicalSort(matrix.transpose(), firstStates);
63 this->bottomTopOrder = std::make_shared<Order>(topStates, bottomStates, numberOfStates, std::move(decomposition), std::move(statesSorted));
64
65 // Build stateMap
66 for (uint_fast64_t state = 0; state < numberOfStates; ++state) {
67 auto const& row = matrix.getRow(state);
68 stateMap[state] = std::vector<uint_fast64_t>();
69 std::set<VariableType> occurringVariables;
70
71 for (auto& entry : matrix.getRow(state)) {
72 // ignore self-loops when there are more transitions
73 if (state != entry.getColumn() || row.getNumberOfEntries() == 1) {
74 if (!subStates[entry.getColumn()] && !bottomTopOrder->contains(state)) {
75 bottomTopOrder->add(state);
76 }
77 stateMap[state].push_back(entry.getColumn());
78 }
79 storm::utility::parametric::gatherOccurringVariables(entry.getValue(), occurringVariables);
80 }
81 if (occurringVariables.empty()) {
82 nonParametricStates.insert(state);
83 }
84
85 for (auto& var : occurringVariables) {
86 occuringStatesAtVariable[var].push_back(state);
87 }
88 occuringVariablesAtState.push_back(std::move(occurringVariables));
89 }
90
91 this->assumptionMaker = new analysis::AssumptionMaker<ValueType, ConstantType>(matrix);
92}
93
94template<typename ValueType, typename ConstantType>
95std::shared_ptr<Order> OrderExtender<ValueType, ConstantType>::getBottomTopOrder() {
96 if (bottomTopOrder == nullptr) {
97 STORM_LOG_ASSERT(model != nullptr, "Model is null.");
98 STORM_LOG_THROW(matrix.getRowCount() == matrix.getColumnCount(), exceptions::NotSupportedException,
99 "Creating order not supported for non-square matrix.");
101 storage::BitVector phiStates;
102 storage::BitVector psiStates;
103 STORM_LOG_ASSERT(formula->isProbabilityOperatorFormula(), "Expected probability operator formula.");
104 if (formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) {
105 phiStates = propositionalChecker.check(formula->asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())
106 ->template asExplicitQualitativeCheckResult<ValueType>()
107 .getTruthValuesVector();
108 psiStates = propositionalChecker.check(formula->asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())
109 ->template asExplicitQualitativeCheckResult<ValueType>()
110 .getTruthValuesVector();
111 } else {
112 STORM_LOG_ASSERT(formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula(), "Expected eventually formula.");
113 phiStates = storage::BitVector(numberOfStates, true);
114 psiStates = propositionalChecker.check(formula->asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())
115 ->template asExplicitQualitativeCheckResult<ValueType>()
116 .getTruthValuesVector();
117 }
118 // Get the maybeStates
119 std::pair<storage::BitVector, storage::BitVector> statesWithProbability01 =
120 utility::graph::performProb01(this->model->getBackwardTransitions(), phiStates, psiStates);
121 storage::BitVector topStates = statesWithProbability01.second;
122 storage::BitVector bottomStates = statesWithProbability01.first;
123
124 STORM_LOG_THROW(topStates.begin() != topStates.end(), exceptions::NotSupportedException, "Formula yields to no 1 states.");
125 STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), exceptions::NotSupportedException, "Formula yields to no zero states.");
126 auto& matrix = this->model->getTransitionMatrix();
127 std::vector<uint64_t> firstStates;
128
129 storm::storage::BitVector subStates(topStates.size(), true);
130 for (auto state : topStates) {
131 firstStates.push_back(state);
132 subStates.set(state, false);
133 }
134 for (auto state : bottomStates) {
135 firstStates.push_back(state);
136 subStates.set(state, false);
137 }
138 cyclic = storm::utility::graph::hasCycle(matrix, subStates);
139 storm::storage::StronglyConnectedComponentDecomposition<ValueType> decomposition;
140 if (cyclic) {
141 storm::storage::StronglyConnectedComponentDecompositionOptions options;
142 options.forceTopologicalSort();
143 decomposition = storm::storage::StronglyConnectedComponentDecomposition<ValueType>(matrix, options);
144 }
145 auto statesSorted = storm::utility::graph::getTopologicalSort(matrix.transpose(), firstStates);
146 bottomTopOrder = std::make_shared<Order>(topStates, bottomStates, numberOfStates, std::move(decomposition), std::move(statesSorted));
147
148 // Build stateMap
149 for (uint_fast64_t state = 0; state < numberOfStates; ++state) {
150 auto const& row = matrix.getRow(state);
151 stateMap[state] = std::vector<uint_fast64_t>();
152 std::set<VariableType> occurringVariables;
153
154 for (auto& entry : matrix.getRow(state)) {
155 // ignore self-loops when there are more transitions
156 if (state != entry.getColumn() || row.getNumberOfEntries() == 1) {
157 // if (!subStates[entry.getColumn()] && !bottomTopOrder->contains(state)) {
158 // bottomTopOrder->add(state);
159 // }
160 stateMap[state].push_back(entry.getColumn());
161 }
162 storm::utility::parametric::gatherOccurringVariables(entry.getValue(), occurringVariables);
163 }
164 if (occurringVariables.empty()) {
165 nonParametricStates.insert(state);
166 }
167
168 for (auto& var : occurringVariables) {
169 occuringStatesAtVariable[var].push_back(state);
170 }
171 occuringVariablesAtState.push_back(std::move(occurringVariables));
172 }
173 }
174
175 if (minValuesInit && maxValuesInit) {
176 continueExtending[bottomTopOrder] = true;
177 usePLA[bottomTopOrder] = true;
178 minValues[bottomTopOrder] = std::move(minValuesInit.get());
179 maxValues[bottomTopOrder] = std::move(maxValuesInit.get());
180 } else {
181 usePLA[bottomTopOrder] = false;
182 }
183 return bottomTopOrder;
184}
185
186template<typename ValueType, typename ConstantType>
187std::tuple<std::shared_ptr<Order>, uint_fast64_t, uint_fast64_t> OrderExtender<ValueType, ConstantType>::toOrder(
189 return this->extendOrder(nullptr, region, monRes, nullptr);
190}
191
192template<typename ValueType, typename ConstantType>
193void OrderExtender<ValueType, ConstantType>::handleAssumption(std::shared_ptr<Order> order,
194 std::shared_ptr<expressions::BinaryRelationExpression> assumption) const {
195 STORM_LOG_ASSERT(assumption != nullptr, "Assumption is null.");
196 STORM_LOG_ASSERT(assumption->getFirstOperand()->isVariable() && assumption->getSecondOperand()->isVariable(), "Expected variable operands.");
197
198 expressions::Variable var1 = assumption->getFirstOperand()->asVariableExpression().getVariable();
199 expressions::Variable var2 = assumption->getSecondOperand()->asVariableExpression().getVariable();
200 auto const& val1 = std::stoul(var1.getName(), nullptr, 0);
201 auto const& val2 = std::stoul(var2.getName(), nullptr, 0);
202
203 STORM_LOG_ASSERT(order->compare(val1, val2) == Order::UNKNOWN, "Order should be UNKNOWN");
204
205 Order::Node* n1 = order->getNode(val1);
206 Order::Node* n2 = order->getNode(val2);
207
208 if (assumption->getRelationType() == expressions::RelationType::Equal) {
209 if (n1 != nullptr && n2 != nullptr) {
210 order->mergeNodes(n1, n2);
211 } else if (n1 != nullptr) {
212 order->addToNode(val2, n1);
213 } else if (n2 != nullptr) {
214 order->addToNode(val1, n2);
215 } else {
216 order->add(val1);
217 order->addToNode(val2, order->getNode(val1));
218 }
219 } else {
220 STORM_LOG_ASSERT(assumption->getRelationType() == expressions::RelationType::Greater, "Expected Greater relation.");
221 if (n1 != nullptr && n2 != nullptr) {
222 order->addRelationNodes(n1, n2);
223 } else if (n1 != nullptr) {
224 order->addBetween(val2, n1, order->getBottom());
225 } else if (n2 != nullptr) {
226 order->addBetween(val1, order->getTop(), n2);
227 } else {
228 order->add(val1);
229 order->addBetween(val2, order->getNode(val1), order->getBottom());
230 }
231 }
232}
233
234template<typename ValueType, typename ConstantType>
235std::tuple<std::shared_ptr<Order>, uint_fast64_t, uint_fast64_t> OrderExtender<ValueType, ConstantType>::extendOrder(
236 std::shared_ptr<Order> order, storm::storage::ParameterRegion<ValueType> region, std::shared_ptr<MonotonicityResult<VariableType>> monRes,
237 std::shared_ptr<expressions::BinaryRelationExpression> assumption) {
238 this->region = region;
239 if (order == nullptr) {
240 order = getBottomTopOrder();
241 if (usePLA[order]) {
242 auto& min = minValues[order];
243 auto& max = maxValues[order];
244 // Try to make the order as complete as possible based on pla results
245 auto& statesSorted = order->getStatesSorted();
246 auto itr = statesSorted.begin();
247 while (itr != statesSorted.end()) {
248 auto state = *itr;
249 auto& successors = stateMap[state];
250 bool all = true;
251 for (uint_fast64_t i = 0; i < successors.size(); ++i) {
252 auto state1 = successors[i];
253 for (uint_fast64_t j = i + 1; j < successors.size(); ++j) {
254 auto state2 = successors[j];
255 if (min[state1] > max[state2]) {
256 if (!order->contains(state1)) {
257 order->add(state1);
258 }
259 if (!order->contains(state2)) {
260 order->add(state2);
261 }
262 order->addRelation(state1, state2, false);
263 } else if (min[state2] > max[state1]) {
264 if (!order->contains(state1)) {
265 order->add(state1);
266 }
267 if (!order->contains(state2)) {
268 order->add(state2);
269 }
270 order->addRelation(state2, state1, false);
271 } else if (min[state1] == max[state2] && max[state1] == min[state2]) {
272 if (!order->contains(state1) && !order->contains(state2)) {
273 order->add(state1);
274 order->addToNode(state2, order->getNode(state1));
275 } else if (!order->contains(state1)) {
276 order->addToNode(state1, order->getNode(state2));
277 } else if (!order->contains(state2)) {
278 order->addToNode(state2, order->getNode(state1));
279 } else {
280 order->merge(state1, state2);
281 STORM_LOG_ASSERT(!order->isInvalid(), "Order is invalid.");
282 }
283 } else {
284 all = false;
285 }
286 }
287 }
288 if (all) {
289 STORM_LOG_INFO("All successors of state " << state << " sorted based on min max values");
290 }
291 ++itr;
292 }
293 }
294 continueExtending[order] = true;
295 }
296 if (continueExtending[order] || assumption != nullptr) {
297 return extendOrder(order, monRes, assumption);
298 } else {
299 auto& res = unknownStatesMap[order];
300 continueExtending[order] = false;
301 return {order, res.first, res.second};
302 }
303}
304
305template<typename ValueType, typename ConstantType>
306std::tuple<std::shared_ptr<Order>, uint_fast64_t, uint_fast64_t> OrderExtender<ValueType, ConstantType>::extendOrder(
307 std::shared_ptr<Order> order, std::shared_ptr<MonotonicityResult<VariableType>> monRes, std::shared_ptr<expressions::BinaryRelationExpression> assumption) {
308 if (assumption != nullptr) {
309 STORM_LOG_INFO("Handling assumption " << *assumption << '\n');
310 handleAssumption(order, assumption);
311 }
312
313 auto currentStateMode = getNextState(order, numberOfStates, false);
314 while (currentStateMode.first != numberOfStates) {
315 STORM_LOG_ASSERT(currentStateMode.first < numberOfStates, "State out of range.");
316 auto& currentState = currentStateMode.first;
317 auto& successors = stateMap[currentState];
318 std::pair<uint_fast64_t, uint_fast64_t> result = {numberOfStates, numberOfStates};
319
320 if (successors.size() == 1) {
321 STORM_LOG_ASSERT(order->contains(successors[0]), "Order does not contain successor.");
322 handleOneSuccessor(order, currentState, successors[0]);
323 } else if (!successors.empty()) {
324 if (order->isOnlyBottomTopOrder()) {
325 order->add(currentState);
326 if (!order->isTrivial(currentState)) {
327 // This state is part of an scc, therefore, we could do forward reasoning here
328 result = extendByForwardReasoning(order, currentState, successors, assumption != nullptr);
329 } else {
330 result = {numberOfStates, numberOfStates};
331 }
332 } else {
333 result = extendNormal(order, currentState, successors, assumption != nullptr);
334 }
335 }
336
337 if (result.first == numberOfStates) {
338 // We did extend the order
339 STORM_LOG_ASSERT(result.second == numberOfStates, "Result second mismatch.");
340 STORM_LOG_ASSERT(order->sortStates(&successors).size() == successors.size(), "Sort states size mismatch.");
341 STORM_LOG_ASSERT(order->contains(currentState) && order->getNode(currentState) != nullptr, "Current state not in order.");
342
343 if (monRes != nullptr) {
344 for (auto& param : occuringVariablesAtState[currentState]) {
345 checkParOnStateMonRes(currentState, order, param, monRes);
346 }
347 }
348 // Get the next state
349 currentStateMode = getNextState(order, currentState, true);
350 } else {
351 STORM_LOG_ASSERT(result.first < numberOfStates, "Result first out of range.");
352 STORM_LOG_ASSERT(result.second < numberOfStates, "Result second out of range.");
353 STORM_LOG_ASSERT(order->compare(result.first, result.second) == Order::UNKNOWN, "Comparison should be UNKNOWN");
354 STORM_LOG_ASSERT(order->compare(result.second, result.first) == Order::UNKNOWN, "Comparison should be UNKNOWN");
355 // Try to add states based on min/max and assumptions, only if we are not in statesToHandle mode
356 if (currentStateMode.second && extendByAssumption(order, result.first, result.second)) {
357 continue;
358 }
359 // We couldn't extend the order
360 if (nonParametricStates.find(currentState) != nonParametricStates.end()) {
361 if (!order->contains(currentState)) {
362 // State is not parametric, so we hope that just adding it between =) and =( will help us
363 order->add(currentState);
364 }
365 currentStateMode = getNextState(order, currentState, true);
366 continue;
367 } else {
368 if (!currentStateMode.second) {
369 // The state was based on statesToHandle, so it is not bad if we cannot continue with this.
370 currentStateMode = getNextState(order, currentState, false);
371 continue;
372 } else {
373 // The state was based on the topological sorting, so we need to return, but first add this state to the states Sorted as we are not done
374 // with it
375 order->addStateSorted(currentState);
376 continueExtending[order] = false;
377 return {order, result.first, result.second};
378 }
379 }
380 }
381 STORM_LOG_ASSERT(order->sortStates(&successors).size() == successors.size(), "Sort states size mismatch after extension.");
382 }
383
384 STORM_LOG_ASSERT(order->getDoneBuilding(), "Order building not done.");
385 if (monRes != nullptr) {
386 // monotonicity result for the in-build checking of monotonicity
387 monRes->setDone();
388 }
389 return std::make_tuple(order, numberOfStates, numberOfStates);
390}
391
392template<typename ValueType, typename ConstantType>
393std::pair<uint_fast64_t, uint_fast64_t> OrderExtender<ValueType, ConstantType>::extendNormal(std::shared_ptr<Order> order, uint_fast64_t currentState,
394 const std::vector<uint_fast64_t>& successors, bool allowMerge) {
395 // when it is cyclic and the current state is part of an SCC we do forwardreasoning
396 if (cyclic && !order->isTrivial(currentState) && order->contains(currentState)) {
397 // Try to extend the order for this scc
398 return extendByForwardReasoning(order, currentState, successors, allowMerge);
399 } else {
400 STORM_LOG_ASSERT(order->isTrivial(currentState) || !order->contains(currentState), "State is neither trivial nor missing.");
401 // Do backward reasoning, all successor states must be in the order
402 return extendByBackwardReasoning(order, currentState, successors, allowMerge);
403 }
404}
405
406template<typename ValueType, typename ConstantType>
407void OrderExtender<ValueType, ConstantType>::handleOneSuccessor(std::shared_ptr<Order> order, uint_fast64_t currentState, uint_fast64_t successor) {
408 STORM_LOG_ASSERT(order->contains(successor), "Order does not contain successor.");
409 if (currentState != successor) {
410 if (order->contains(currentState)) {
411 order->merge(currentState, successor);
412 } else {
413 order->addToNode(currentState, order->getNode(successor));
414 }
415 }
416}
417
418template<typename ValueType, typename ConstantType>
419std::pair<uint_fast64_t, uint_fast64_t> OrderExtender<ValueType, ConstantType>::extendByBackwardReasoning(std::shared_ptr<Order> order,
420 uint_fast64_t currentState,
421 std::vector<uint_fast64_t> const& successors,
422 bool allowMerge) {
423 STORM_LOG_ASSERT(!order->isOnlyBottomTopOrder(), "Order is only bottom-top.");
424 STORM_LOG_ASSERT(successors.size() > 1, "Expected multiple successors.");
425
426 bool pla = (usePLA.find(order) != usePLA.end() && usePLA.at(order));
427 std::vector<uint_fast64_t> sortedSuccs;
428
429 if (pla && (continueExtending.find(order) == continueExtending.end() || continueExtending.at(order))) {
430 for (auto& state1 : successors) {
431 if (sortedSuccs.size() == 0) {
432 sortedSuccs.push_back(state1);
433 } else {
434 bool added = false;
435 for (auto itr = sortedSuccs.begin(); itr != sortedSuccs.end(); ++itr) {
436 auto& state2 = *itr;
437 auto compareRes = order->compareFast(state1, state2);
438 if (compareRes == Order::NodeComparison::UNKNOWN) {
439 compareRes = addStatesBasedOnMinMax(order, state1, state2);
440 }
441 if (compareRes == Order::NodeComparison::UNKNOWN) {
442 // If fast comparison did not help, we continue by checking "slow" comparison
443 compareRes = order->compare(state1, state2);
444 }
445 if (compareRes == Order::NodeComparison::ABOVE || compareRes == Order::NodeComparison::SAME) {
446 // insert at current pointer (while keeping other values)
447 sortedSuccs.insert(itr, state1);
448 added = true;
449 break;
450 } else if (compareRes == Order::NodeComparison::UNKNOWN) {
451 continueExtending[order] = false;
452 return {state1, state2};
453 }
454 }
455 if (!added) {
456 sortedSuccs.push_back(state1);
457 }
458 }
459 }
460 } else {
461 auto temp = order->sortStatesUnorderedPair(&successors);
462 if (temp.first.first != numberOfStates) {
463 return temp.first;
464 } else {
465 sortedSuccs = std::move(temp.second);
466 }
467 }
468
469 if (order->compare(sortedSuccs[0], sortedSuccs[sortedSuccs.size() - 1]) == Order::SAME) {
470 if (!order->contains(currentState)) {
471 order->addToNode(currentState, order->getNode(sortedSuccs[0]));
472 } else {
473 order->merge(currentState, sortedSuccs[0]);
474 }
475 } else {
476 if (!order->contains(sortedSuccs[0])) {
477 STORM_LOG_ASSERT(order->isBottomState(sortedSuccs[sortedSuccs.size() - 1]), "Expected bottom state.");
478 STORM_LOG_ASSERT(sortedSuccs.size() == 2, "Expected 2 successors.");
479 order->addAbove(sortedSuccs[0], order->getBottom());
480 }
481 if (!order->contains(sortedSuccs[sortedSuccs.size() - 1])) {
482 STORM_LOG_ASSERT(order->isTopState(sortedSuccs[0]), "Expected top state.");
483 STORM_LOG_ASSERT(sortedSuccs.size() == 2, "Expected 2 successors.");
484 order->addBelow(sortedSuccs[sortedSuccs.size() - 1], order->getTop());
485 }
486 // sortedSuccs[0] is highest
487 if (!order->contains(currentState)) {
488 order->addBetween(currentState, sortedSuccs[0], sortedSuccs[sortedSuccs.size() - 1]);
489 } else {
490 order->addRelation(sortedSuccs[0], currentState, allowMerge);
491 order->addRelation(currentState, sortedSuccs[sortedSuccs.size() - 1], allowMerge);
492 }
493 }
494 STORM_LOG_ASSERT(order->contains(currentState) && order->compare(order->getNode(currentState), order->getBottom()) == Order::ABOVE &&
495 order->compare(order->getNode(currentState), order->getTop()) == Order::BELOW,
496 "Order is not as expected.");
497 return {numberOfStates, numberOfStates};
498}
499
500template<typename ValueType, typename ConstantType>
501std::pair<uint_fast64_t, uint_fast64_t> OrderExtender<ValueType, ConstantType>::extendByForwardReasoning(std::shared_ptr<Order> order,
502 uint_fast64_t currentState,
503 std::vector<uint_fast64_t> const& successors,
504 bool allowMerge) {
505 STORM_LOG_ASSERT(successors.size() > 1, "Expected multiple successors.");
506 STORM_LOG_ASSERT(order->contains(currentState), "Current state not in order.");
507 STORM_LOG_ASSERT(cyclic, "Expected cyclic.");
508
509 std::vector<uint_fast64_t> statesSorted;
510 statesSorted.push_back(currentState);
511 bool pla = (usePLA.find(order) != usePLA.end() && usePLA.at(order));
512 // Go over all states
513 bool oneUnknown = false;
514 bool unknown = false;
515 uint_fast64_t s1 = numberOfStates;
516 uint_fast64_t s2 = numberOfStates;
517 for (auto& state : successors) {
518 unknown = false;
519 bool added = false;
520 for (auto itr = statesSorted.begin(); itr != statesSorted.end(); ++itr) {
521 auto compareRes = order->compareFast(state, (*itr));
522 if (pla && compareRes == Order::NodeComparison::UNKNOWN) {
523 compareRes = addStatesBasedOnMinMax(order, state, (*itr));
524 }
525 if (compareRes == Order::NodeComparison::UNKNOWN) {
526 compareRes = order->compare(state, *itr);
527 }
528 if (compareRes == Order::NodeComparison::ABOVE || compareRes == Order::NodeComparison::SAME) {
529 if (!order->contains(state) && compareRes == Order::NodeComparison::ABOVE) {
530 order->add(state);
531 order->addStateToHandle(state);
532 }
533 added = true;
534 // insert at current pointer (while keeping other values)
535 statesSorted.insert(itr, state);
536 break;
537 } else if (compareRes == Order::NodeComparison::UNKNOWN && !oneUnknown) {
538 // We miss state in the result.
539 s1 = state;
540 s2 = *itr;
541 oneUnknown = true;
542 added = true;
543 break;
544 } else if (compareRes == Order::NodeComparison::UNKNOWN && oneUnknown) {
545 unknown = true;
546 added = true;
547 break;
548 }
549 }
550 if (!(unknown && oneUnknown) && !added) {
551 // State will be last in the list
552 statesSorted.push_back(state);
553 }
554 if (unknown && oneUnknown) {
555 break;
556 }
557 }
558 if (!unknown && oneUnknown) {
559 STORM_LOG_ASSERT(statesSorted.size() == successors.size(), "States sorted size mismatch.");
560 s2 = numberOfStates;
561 }
562
563 if (s1 == numberOfStates) {
564 STORM_LOG_ASSERT(statesSorted.size() == successors.size() + 1, "States sorted size mismatch.");
565 // all could be sorted, no need to do anything
566 } else if (s2 == numberOfStates) {
567 if (!order->contains(s1)) {
568 order->add(s1);
569 }
570
571 if (statesSorted[0] == currentState) {
572 order->addRelation(s1, statesSorted[0], allowMerge);
573 STORM_LOG_ASSERT((order->compare(s1, statesSorted[0]) == Order::ABOVE) ||
574 (allowMerge && (order->compare(s1, statesSorted[statesSorted.size() - 1]) == Order::SAME)),
575 "Order is not as expected.");
576 order->addRelation(s1, statesSorted[statesSorted.size() - 1], allowMerge);
577 STORM_LOG_ASSERT((order->compare(s1, statesSorted[statesSorted.size() - 1]) == Order::ABOVE) ||
578 (allowMerge && (order->compare(s1, statesSorted[statesSorted.size() - 1]) == Order::SAME)),
579 "Order is not as expected.");
580 order->addStateToHandle(s1);
581 } else if (statesSorted[statesSorted.size() - 1] == currentState) {
582 order->addRelation(statesSorted[0], s1, allowMerge);
583 STORM_LOG_ASSERT((order->compare(s1, statesSorted[0]) == Order::BELOW) ||
584 (allowMerge && (order->compare(s1, statesSorted[statesSorted.size() - 1]) == Order::SAME)),
585 "Order is not as expected.");
586 order->addRelation(statesSorted[statesSorted.size() - 1], s1, allowMerge);
587 STORM_LOG_ASSERT((order->compare(s1, statesSorted[statesSorted.size() - 1]) == Order::BELOW) ||
588 (allowMerge && (order->compare(s1, statesSorted[statesSorted.size() - 1]) == Order::SAME)),
589 "Order is not as expected.");
590 order->addStateToHandle(s1);
591 } else {
592 bool continueSearch = true;
593 for (auto& entry : matrix.getRow(currentState)) {
594 if (entry.getColumn() == s1) {
595 if (entry.getValue().isConstant()) {
596 continueSearch = false;
597 }
598 }
599 }
600 if (continueSearch) {
601 for (auto& i : statesSorted) {
602 if (order->compare(i, s1) == Order::UNKNOWN) {
603 return {i, s1};
604 }
605 }
606 }
607 }
608 } else {
609 return {s1, s2};
610 }
611 STORM_LOG_ASSERT(order->contains(currentState) && order->compare(order->getNode(currentState), order->getBottom()) == Order::ABOVE &&
612 order->compare(order->getNode(currentState), order->getTop()) == Order::BELOW,
613 "Order is not as expected.");
614 return {numberOfStates, numberOfStates};
615}
616
617template<typename ValueType, typename ConstantType>
618bool OrderExtender<ValueType, ConstantType>::extendByAssumption(std::shared_ptr<Order> order, uint_fast64_t state1, uint_fast64_t state2) {
619 bool usePLANow = usePLA.find(order) != usePLA.end() && usePLA[order];
620 STORM_LOG_ASSERT(order->compare(state1, state2) == Order::UNKNOWN, "Comparison should be UNKNOWN");
621 auto assumptions = usePLANow ? assumptionMaker->createAndCheckAssumptions(state1, state2, order, region, minValues[order], maxValues[order])
622 : assumptionMaker->createAndCheckAssumptions(state1, state2, order, region);
623 if (assumptions.size() == 1 && assumptions.begin()->second == AssumptionStatus::VALID) {
624 handleAssumption(order, assumptions.begin()->first);
625 // Assumptions worked, we continue
626 return true;
627 }
628 return false;
629}
630
631template<typename ValueType, typename ConstantType>
632Order::NodeComparison OrderExtender<ValueType, ConstantType>::addStatesBasedOnMinMax(std::shared_ptr<Order> order, uint_fast64_t state1,
633 uint_fast64_t state2) const {
634 STORM_LOG_ASSERT(order->compareFast(state1, state2) == Order::UNKNOWN, "Fast comparison should be UNKNOWN");
635 STORM_LOG_ASSERT(minValues.find(order) != minValues.end(), "MinValues missing for order.");
636 std::vector<ConstantType> const& mins = minValues.at(order);
637 std::vector<ConstantType> const& maxs = maxValues.at(order);
638 if (mins[state1] == maxs[state1] && mins[state2] == maxs[state2] && mins[state1] == mins[state2]) {
639 if (order->contains(state1)) {
640 if (order->contains(state2)) {
641 order->merge(state1, state2);
642 STORM_LOG_ASSERT(!order->isInvalid(), "Order is invalid after merge.");
643 } else {
644 order->addToNode(state2, order->getNode(state1));
645 }
646 }
647 return Order::SAME;
648 } else if (mins[state1] > maxs[state2]) {
649 // state 1 will always be larger than state2
650 if (!order->contains(state1)) {
651 order->add(state1);
652 }
653 if (!order->contains(state2)) {
654 order->add(state2);
655 }
656 STORM_LOG_ASSERT(order->compare(state1, state2) != Order::BELOW, "State1 should not be below state2");
657 STORM_LOG_ASSERT(order->compare(state1, state2) != Order::SAME, "State1 should not be same as state2");
658 order->addRelation(state1, state2);
659
660 return Order::ABOVE;
661 } else if (mins[state2] > maxs[state1]) {
662 // state2 will always be larger than state1
663 if (!order->contains(state1)) {
664 order->add(state1);
665 }
666 if (!order->contains(state2)) {
667 order->add(state2);
668 }
669 STORM_LOG_ASSERT(order->compare(state2, state1) != Order::BELOW, "State2 should not be below state1");
670 STORM_LOG_ASSERT(order->compare(state2, state1) != Order::SAME, "State2 should not be same as state1");
671 order->addRelation(state2, state1);
672 return Order::BELOW;
673 } else {
674 // Couldn't add relation between state1 and state 2 based on min/max values;
675 return Order::UNKNOWN;
676 }
677}
678
679template<typename ValueType, typename ConstantType>
681 if (model != nullptr) {
682 // Use parameter lifting modelchecker to get initial min/max values for order creation
684 std::unique_ptr<modelchecker::CheckResult> checkResult;
685 auto env = Environment();
686 boost::optional<modelchecker::CheckTask<logic::Formula, ValueType>> checkTask;
687 if (this->formula->hasQuantitativeResult()) {
689 } else {
690 storm::logic::OperatorInformation opInfo(boost::none, boost::none);
691 auto newFormula =
692 std::make_shared<storm::logic::ProbabilityOperatorFormula>(formula->asProbabilityOperatorFormula().getSubformula().asSharedPointer(), opInfo);
694 }
695 STORM_LOG_THROW(plaModelChecker.canHandle(model, checkTask.get()), exceptions::NotSupportedException, "Cannot handle this formula.");
696 bool const allowModelSimplification = false; // make sure that the results align with the input model
697 plaModelChecker.specify(env, model, checkTask.get(), std::nullopt, nullptr, allowModelSimplification);
698
701 plaModelChecker.check(env, annotatedRegion, solver::OptimizationDirection::Minimize)->template asExplicitQuantitativeCheckResult<ConstantType>();
703 plaModelChecker.check(env, annotatedRegion, solver::OptimizationDirection::Maximize)->template asExplicitQuantitativeCheckResult<ConstantType>();
704 minValuesInit = minCheck.getValueVector();
705 maxValuesInit = maxCheck.getValueVector();
706 STORM_LOG_ASSERT(minValuesInit->size() == numberOfStates, "MinValuesInit size mismatch.");
707 STORM_LOG_ASSERT(maxValuesInit->size() == numberOfStates, "MaxValuesInit size mismatch.");
708 }
709}
710
711template<typename ValueType, typename ConstantType>
712void OrderExtender<ValueType, ConstantType>::setMinMaxValues(std::shared_ptr<Order> order, std::vector<ConstantType>&& minValues,
713 std::vector<ConstantType>&& maxValues) {
714 STORM_LOG_ASSERT(minValues.size() == numberOfStates, "MinValues size mismatch.");
715 STORM_LOG_ASSERT(maxValues.size() == numberOfStates, "MaxValues size mismatch.");
716 usePLA[order] = true;
717 if (unknownStatesMap.find(order) != unknownStatesMap.end()) {
718 auto& unknownStates = unknownStatesMap[order];
719 if (unknownStates.first != numberOfStates) {
720 continueExtending[order] =
721 minValues[unknownStates.first] >= maxValues[unknownStates.second] || minValues[unknownStates.second] >= maxValues[unknownStates.first];
722 } else {
723 continueExtending[order] = true;
724 }
725 } else {
726 continueExtending[order] = true;
727 }
728 this->minValues[order] = std::move(minValues);
729 this->maxValues[order] = std::move(maxValues);
730}
731
732template<typename ValueType, typename ConstantType>
733void OrderExtender<ValueType, ConstantType>::setMinValues(std::shared_ptr<Order> order, std::vector<ConstantType>&& minValues) {
734 STORM_LOG_ASSERT(minValues.size() == numberOfStates, "MinValues size mismatch.");
735 auto& maxValues = this->maxValues[order];
736 usePLA[order] = this->maxValues.find(order) != this->maxValues.end();
737 if (maxValues.size() == 0) {
738 continueExtending[order] = false;
739 } else if (unknownStatesMap.find(order) != unknownStatesMap.end()) {
740 auto& unknownStates = unknownStatesMap[order];
741 if (unknownStates.first != numberOfStates) {
742 continueExtending[order] =
743 minValues[unknownStates.first] >= maxValues[unknownStates.second] || minValues[unknownStates.second] >= maxValues[unknownStates.first];
744 } else {
745 continueExtending[order] = true;
746 }
747 } else {
748 continueExtending[order] = true;
749 }
750 this->minValues[order] = std::move(minValues);
751}
752
753template<typename ValueType, typename ConstantType>
754void OrderExtender<ValueType, ConstantType>::setMaxValues(std::shared_ptr<Order> order, std::vector<ConstantType>&& maxValues) {
755 STORM_LOG_ASSERT(maxValues.size() == numberOfStates, "MaxValues size mismatch.");
756 usePLA[order] = this->minValues.find(order) != this->minValues.end();
757 auto& minValues = this->minValues[order];
758 if (minValues.size() == 0) {
759 continueExtending[order] = false;
760 } else if (unknownStatesMap.find(order) != unknownStatesMap.end()) {
761 auto& unknownStates = unknownStatesMap[order];
762 if (unknownStates.first != numberOfStates) {
763 continueExtending[order] =
764 minValues[unknownStates.first] >= maxValues[unknownStates.second] || minValues[unknownStates.second] >= maxValues[unknownStates.first];
765 } else {
766 continueExtending[order] = true;
767 }
768 } else {
769 continueExtending[order] = true;
770 }
771 this->maxValues[order] = std::move(maxValues); // maxCheck->asExplicitQuantitativeCheckResult<ConstantType>().getValueVector();
772}
773template<typename ValueType, typename ConstantType>
774void OrderExtender<ValueType, ConstantType>::setMinValuesInit(std::vector<ConstantType>&& minValues) {
775 STORM_LOG_ASSERT(minValues.size() == numberOfStates, "MinValues size mismatch.");
776 this->minValuesInit = std::move(minValues);
777}
778
779template<typename ValueType, typename ConstantType>
780void OrderExtender<ValueType, ConstantType>::setMaxValuesInit(std::vector<ConstantType>&& maxValues) {
781 STORM_LOG_ASSERT(maxValues.size() == numberOfStates, "MaxValues size mismatch.");
782 this->maxValuesInit = std::move(maxValues); // maxCheck->asExplicitQuantitativeCheckResult<ConstantType>().getValueVector();
783}
784
785template<typename ValueType, typename ConstantType>
786void OrderExtender<ValueType, ConstantType>::checkParOnStateMonRes(uint_fast64_t s, std::shared_ptr<Order> order,
788 std::shared_ptr<MonotonicityResult<VariableType>> monResult) {
789 auto mon = monotonicityChecker.checkLocalMonotonicity(order, s, param, region);
790 monResult->updateMonotonicityResult(param, mon);
791}
792
793template<typename ValueType, typename ConstantType>
794void OrderExtender<ValueType, ConstantType>::setUnknownStates(std::shared_ptr<Order> order, uint_fast64_t state1, uint_fast64_t state2) {
795 STORM_LOG_ASSERT(state1 != numberOfStates && state2 != numberOfStates, "States should not be numberOfStates.");
796 unknownStatesMap[order] = {state1, state2};
797}
798
799template<typename ValueType, typename ConstantType>
800std::pair<uint_fast64_t, uint_fast64_t> OrderExtender<ValueType, ConstantType>::getUnknownStates(std::shared_ptr<Order> order) const {
801 if (unknownStatesMap.find(order) != unknownStatesMap.end()) {
802 return unknownStatesMap.at(order);
803 }
804 return {numberOfStates, numberOfStates};
805}
806
807template<typename ValueType, typename ConstantType>
808void OrderExtender<ValueType, ConstantType>::setUnknownStates(std::shared_ptr<Order> orderOriginal, std::shared_ptr<Order> orderCopy) {
809 STORM_LOG_ASSERT(unknownStatesMap.find(orderCopy) == unknownStatesMap.end(), "OrderCopy already in unknownStatesMap.");
810 unknownStatesMap.insert({orderCopy, {unknownStatesMap[orderOriginal].first, unknownStatesMap[orderOriginal].second}});
811}
812
813template<typename ValueType, typename ConstantType>
814void OrderExtender<ValueType, ConstantType>::copyMinMax(std::shared_ptr<Order> orderOriginal, std::shared_ptr<Order> orderCopy) {
815 usePLA[orderCopy] = usePLA[orderOriginal];
816 if (usePLA[orderCopy]) {
817 minValues[orderCopy] = minValues[orderOriginal];
818 STORM_LOG_ASSERT(maxValues.find(orderOriginal) != maxValues.end(), "MaxValues missing for orderOriginal.");
819 maxValues[orderCopy] = maxValues[orderOriginal];
820 }
821 continueExtending[orderCopy] = continueExtending[orderOriginal];
822}
823
824template<typename ValueType, typename ConstantType>
825std::pair<uint_fast64_t, bool> OrderExtender<ValueType, ConstantType>::getNextState(std::shared_ptr<Order> order, uint_fast64_t currentState, bool done) {
826 if (done && currentState != numberOfStates) {
827 order->setDoneState(currentState);
828 }
829 if (cyclic && order->existsStateToHandle()) {
830 return order->getStateToHandle();
831 }
832 if (currentState == numberOfStates) {
833 return order->getNextStateNumber();
834 }
835 if (currentState != numberOfStates) {
836 return order->getNextStateNumber();
837 }
838 return {numberOfStates, true};
839}
840
841template<typename ValueType, typename ConstantType>
842bool OrderExtender<ValueType, ConstantType>::isHope(std::shared_ptr<Order> order) {
843 STORM_LOG_ASSERT(unknownStatesMap.find(order) != unknownStatesMap.end(), "Order not in unknownStatesMap.");
844 STORM_LOG_ASSERT(!order->getDoneBuilding(), "Order building unexpectedly done.");
845 // First check if bounds helped us
846 bool yesThereIsHope = continueExtending[order];
847 return yesThereIsHope;
848}
849template<typename ValueType, typename ConstantType>
853template<typename ValueType, typename ConstantType>
854const std::vector<std::set<typename OrderExtender<ValueType, ConstantType>::VariableType>>&
858
861} // namespace analysis
862} // namespace storm
void copyMinMax(std::shared_ptr< Order > orderOriginal, std::shared_ptr< Order > orderCopy)
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
void setMaxValues(std::shared_ptr< Order > order, std::vector< ConstantType > &&maxValues)
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::shared_ptr< expressions::BinaryRelationExpression > assumption=nullptr)
Extends the order for the given region.
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.
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)
void initializeMinMaxValues(storage::ParameterRegion< ValueType > region)
bool isHope(std::shared_ptr< Order > order)
NodeComparison
Constants for comparison of nodes/states.
Definition Order.h:18
std::string const & getName() const
Retrieves the name of the variable.
Definition Variable.cpp:46
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, bool graphPreserving=true) override
std::unique_ptr< CheckResult > check(Environment const &env, AnnotatedRegion< ParametricType > &region, 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.
Definition Model.h:30
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
void set(uint64_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.
A class that holds a possibly non-square matrix in the compressed row storage format.
This class represents the decomposition of a graph-like structure into its strongly connected compone...
#define STORM_LOG_INFO(message)
Definition logging.h:27
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
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:393
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.
Definition graph.cpp:1845
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.
Definition graph.cpp:136
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.
Nodes of the Reachability Order.
Definition Order.h:28
StronglyConnectedComponentDecompositionOptions & forceTopologicalSort(bool value=true)
Enforces that the returned SCCs are sorted in a topological order.