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