Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
MenuGameRefiner.cpp
Go to the documentation of this file.
2
5
10
13#include "storm/utility/dd.h"
16
18
20
22
24
25#include "storm-config.h"
27
28namespace storm::gbar {
29namespace abstraction {
30
32
33RefinementPredicates::RefinementPredicates(Source const& source, std::vector<storm::expressions::Expression> const& predicates)
34 : source(source), predicates(predicates) {
35 // Intentionally left empty.
36}
37
41
42std::vector<storm::expressions::Expression> const& RefinementPredicates::getPredicates() const {
43 return predicates;
44}
45
46void RefinementPredicates::addPredicates(std::vector<storm::expressions::Expression> const& newPredicates) {
47 this->predicates.insert(this->predicates.end(), newPredicates.begin(), newPredicates.end());
48}
49
50template<storm::dd::DdType Type, typename ValueType>
52 storm::dd::Bdd<Type> const& spanningTree)
53 : maxProbabilities(maxProbabilities), spanningTree(spanningTree) {
54 // Intentionally left empty.
55}
56
57template<storm::dd::DdType Type>
63
64template<storm::dd::DdType Type, typename ValueType>
66 storm::dd::Bdd<Type> const& pivotState, storm::OptimizationDirection fromDirection,
67 boost::optional<SymbolicMostProbablePathsResult<Type, ValueType>> const& symbolicMostProbablePathsResult)
68 : pivotState(pivotState), fromDirection(fromDirection), symbolicMostProbablePathsResult(symbolicMostProbablePathsResult) {
69 // Intentionally left empty.
70}
71
72template<storm::dd::DdType Type, typename ValueType>
73MenuGameRefiner<Type, ValueType>::MenuGameRefiner(MenuGameAbstractor<Type, ValueType>& abstractor, std::unique_ptr<storm::solver::SmtSolver>&& smtSolver,
74 MenuGameRefinerOptions const& options)
75 : abstractor(abstractor),
76 useInterpolation(storm::settings::getModule<storm::settings::modules::AbstractionSettings>().isUseInterpolationSet()),
77 splitAll(false),
78 splitPredicates(false),
79 rankPredicates(false),
80 addedAllGuardsFlag(false),
81 refinementPredicatesToInject(options.refinementPredicates),
82 pivotSelectionHeuristic(),
83 splitter(),
84 equivalenceChecker(std::move(smtSolver)) {
86
87 pivotSelectionHeuristic = abstractionSettings.getPivotSelectionHeuristic();
89 splitAll = splitMode == AbstractionSettings::SplitMode::All;
90 splitPredicates = splitMode == AbstractionSettings::SplitMode::NonGuard;
91 rankPredicates = abstractionSettings.isRankRefinementPredicatesSet();
92 addPredicatesEagerly = abstractionSettings.isUseEagerRefinementSet();
93
94 equivalenceChecker.addConstraints(abstractor.getAbstractionInformation().getConstraints());
95 if (abstractionSettings.isAddAllGuardsSet()) {
96 std::vector<storm::expressions::Expression> guards;
97
98 std::pair<uint64_t, uint64_t> player1Choices = this->abstractor.get().getPlayer1ChoiceRange();
99 for (uint64_t index = player1Choices.first; index < player1Choices.second; ++index) {
100 storm::expressions::Expression guard = this->abstractor.get().getGuard(index);
101 if (!guard.isTrue() && !guard.isFalse()) {
102 guards.push_back(guard);
103 }
104 }
105 performRefinement(createGlobalRefinement(preprocessPredicates(guards, RefinementPredicates::Source::InitialGuard)));
106
107 this->abstractor.get().notifyGuardsArePredicates();
108 addedAllGuardsFlag = true;
109 }
110 if (abstractionSettings.isAddAllInitialExpressionsSet()) {
111 storm::expressions::Expression initialExpression = this->abstractor.get().getInitialExpression();
112 performRefinement(createGlobalRefinement(preprocessPredicates({initialExpression}, RefinementPredicates::Source::InitialExpression)));
113 }
114}
115
116template<storm::dd::DdType Type, typename ValueType>
117void MenuGameRefiner<Type, ValueType>::refine(std::vector<storm::expressions::Expression> const& predicates, bool allowInjection) const {
118 performRefinement(createGlobalRefinement(preprocessPredicates(predicates, RefinementPredicates::Source::Manual)), allowInjection);
119}
120
121template<storm::dd::DdType Type, typename ValueType>
123 storm::dd::Bdd<Type> const& transitionFilter) {
124 storm::dd::Add<Type, ValueType> maxProbabilities = game.getInitialStates().template toAdd<ValueType>();
125
127 storm::dd::Bdd<Type> spanningTree = game.getManager().getBddZero();
128
129 storm::dd::Add<Type, ValueType> transitionMatrix =
131 .template toAdd<ValueType>() *
133 .sumAbstract(game.getPlayer2Variables());
134
135 std::set<storm::expressions::Variable> variablesToAbstract(game.getRowVariables());
136 variablesToAbstract.insert(game.getPlayer1Variables().begin(), game.getPlayer1Variables().end());
137 variablesToAbstract.insert(game.getProbabilisticBranchingVariables().begin(), game.getProbabilisticBranchingVariables().end());
138 while (!border.isZero()) {
139 // Determine the new maximal probabilities to all states.
140 storm::dd::Add<Type, ValueType> tmp = border.template toAdd<ValueType>() * transitionMatrix * maxProbabilities;
141 storm::dd::Bdd<Type> newMaxProbabilityChoices = tmp.maxAbstractRepresentative(variablesToAbstract);
142 storm::dd::Add<Type, ValueType> newMaxProbabilities = tmp.maxAbstract(variablesToAbstract).swapVariables(game.getRowColumnMetaVariablePairs());
143
144 // Determine the probability values for which states strictly increased.
145 storm::dd::Bdd<Type> updateStates = newMaxProbabilities.greater(maxProbabilities);
146 maxProbabilities = updateStates.ite(newMaxProbabilities, maxProbabilities);
147
148 // Delete all edges in the spanning tree that lead to states that need to be updated.
149 spanningTree &= ((!updateStates).swapVariables(game.getRowColumnMetaVariablePairs()));
150
151 // Add all edges that achieve the new maximal value to the spanning tree.
152 spanningTree |= updateStates.swapVariables(game.getRowColumnMetaVariablePairs()) && newMaxProbabilityChoices;
153
154 // Continue exploration from states that have been updated.
155 border = updateStates;
156 }
157
158 return SymbolicMostProbablePathsResult<Type, ValueType>(maxProbabilities, spanningTree);
159}
160
161template<storm::dd::DdType Type, typename ValueType>
164 PivotStateCandidatesResult<Type> const& pivotStateCandidateResult,
165 boost::optional<SymbolicQualitativeGameResultMinMax<Type>> const& qualitativeResult,
166 boost::optional<SymbolicQuantitativeGameResultMinMax<Type, ValueType>> const& quantitativeResult) {
167 // Get easy access to strategies.
168 storm::dd::Bdd<Type> minPlayer1Strategy;
169 storm::dd::Bdd<Type> minPlayer2Strategy;
170 storm::dd::Bdd<Type> maxPlayer1Strategy;
171 storm::dd::Bdd<Type> maxPlayer2Strategy;
172 if (qualitativeResult) {
173 minPlayer1Strategy = qualitativeResult.get().prob0Min.getPlayer1Strategy();
174 minPlayer2Strategy = qualitativeResult.get().prob0Min.getPlayer2Strategy();
175 maxPlayer1Strategy = qualitativeResult.get().prob1Max.getPlayer1Strategy();
176 maxPlayer2Strategy = qualitativeResult.get().prob1Max.getPlayer2Strategy();
177 } else if (quantitativeResult) {
178 minPlayer1Strategy = quantitativeResult.get().min.getPlayer1Strategy();
179 minPlayer2Strategy = quantitativeResult.get().min.getPlayer2Strategy();
180 maxPlayer1Strategy = quantitativeResult.get().max.getPlayer1Strategy();
181 maxPlayer2Strategy = quantitativeResult.get().max.getPlayer2Strategy();
182 } else {
183 STORM_LOG_ASSERT(false, "Either qualitative or quantitative result is required.");
184 }
185
186 storm::dd::Bdd<Type> pivotStates = pivotStateCandidateResult.pivotStates;
187
189 // Set up used variables.
190 storm::dd::Bdd<Type> initialStates = game.getInitialStates();
191 std::set<storm::expressions::Variable> const& rowVariables = game.getRowVariables();
192 std::set<storm::expressions::Variable> const& columnVariables = game.getColumnVariables();
193 storm::dd::Bdd<Type> transitionsMin = pivotStateCandidateResult.reachableTransitionsMin;
194 storm::dd::Bdd<Type> transitionsMax = pivotStateCandidateResult.reachableTransitionsMax;
195 storm::dd::Bdd<Type> frontierMin = initialStates;
196 storm::dd::Bdd<Type> frontierMax = initialStates;
197 storm::dd::Bdd<Type> frontierPivotStates = frontierMin && pivotStates;
198
199 // Check whether we have pivot states on the very first level.
200 uint64_t level = 0;
201 bool foundPivotState = !frontierPivotStates.isZero();
202 if (foundPivotState) {
203 STORM_LOG_TRACE("Picked pivot state from " << frontierPivotStates.getNonZeroCount() << " candidates on level " << level << ", "
204 << pivotStates.getNonZeroCount() << " candidates in total.");
205 return SymbolicPivotStateResult<Type, ValueType>(frontierPivotStates.existsAbstractRepresentative(rowVariables),
206 storm::OptimizationDirection::Minimize);
207 } else {
208 // Otherwise, we perform a simulatenous BFS in the sense that we make one step in both the min and max
209 // transitions and check for pivot states we encounter.
210 while (!foundPivotState) {
211 frontierMin = frontierMin.relationalProduct(transitionsMin, rowVariables, columnVariables);
212 frontierMax = frontierMax.relationalProduct(transitionsMax, rowVariables, columnVariables);
213 ++level;
214
215 storm::dd::Bdd<Type> frontierMinPivotStates = frontierMin && pivotStates;
216 storm::dd::Bdd<Type> frontierMaxPivotStates = frontierMax && pivotStates;
217 uint64_t numberOfPivotStateCandidatesOnLevel = frontierMinPivotStates.getNonZeroCount() + frontierMaxPivotStates.getNonZeroCount();
218
219 if (!frontierMinPivotStates.isZero() || !frontierMaxPivotStates.isZero()) {
220 if (quantitativeResult) {
221 storm::dd::Add<Type, ValueType> frontierMinPivotStatesAdd = frontierMinPivotStates.template toAdd<ValueType>();
222 storm::dd::Add<Type, ValueType> frontierMaxPivotStatesAdd = frontierMaxPivotStates.template toAdd<ValueType>();
223
225 frontierMinPivotStatesAdd * quantitativeResult.get().max.values - frontierMinPivotStatesAdd * quantitativeResult.get().min.values;
227 frontierMaxPivotStatesAdd * quantitativeResult.get().max.values - frontierMaxPivotStatesAdd * quantitativeResult.get().min.values;
228
229 ValueType diffValue;
231 if (diffMin.getMax() >= diffMax.getMax()) {
232 direction = storm::OptimizationDirection::Minimize;
233 diffValue = diffMin.getMax();
234 } else {
235 direction = storm::OptimizationDirection::Maximize;
236 diffValue = diffMax.getMax();
237 }
238
239 STORM_LOG_TRACE("Picked pivot state with difference " << diffValue << " from " << numberOfPivotStateCandidatesOnLevel
240 << " candidates on level " << level << ", " << pivotStates.getNonZeroCount()
241 << " candidates in total.");
242 return SymbolicPivotStateResult<Type, ValueType>(direction == storm::OptimizationDirection::Minimize
243 ? diffMin.maxAbstractRepresentative(rowVariables)
244 : diffMax.maxAbstractRepresentative(rowVariables),
245 direction);
246 } else {
247 STORM_LOG_TRACE("Picked pivot state from " << numberOfPivotStateCandidatesOnLevel << " candidates on level " << level << ", "
248 << pivotStates.getNonZeroCount() << " candidates in total.");
249
251 if (!frontierMinPivotStates.isZero()) {
252 direction = storm::OptimizationDirection::Minimize;
253 } else {
254 direction = storm::OptimizationDirection::Maximize;
255 }
256
257 return SymbolicPivotStateResult<Type, ValueType>(direction == storm::OptimizationDirection::Minimize
258 ? frontierMinPivotStates.existsAbstractRepresentative(rowVariables)
259 : frontierMaxPivotStates.existsAbstractRepresentative(rowVariables),
260 direction);
261 }
262 }
263 }
264 }
265 } else {
266 // Compute the most probable paths to the reachable states and the corresponding spanning trees.
267 SymbolicMostProbablePathsResult<Type, ValueType> minSymbolicMostProbablePathsResult =
268 getMostProbablePathSpanningTree(game, minPlayer1Strategy && minPlayer2Strategy);
269 SymbolicMostProbablePathsResult<Type, ValueType> maxSymbolicMostProbablePathsResult =
270 getMostProbablePathSpanningTree(game, maxPlayer1Strategy && maxPlayer2Strategy);
271 storm::dd::Bdd<Type> selectedPivotState;
272
273 storm::dd::Add<Type, ValueType> score = pivotStates.template toAdd<ValueType>() * minSymbolicMostProbablePathsResult.maxProbabilities.maximum(
274 maxSymbolicMostProbablePathsResult.maxProbabilities);
275
276 if (heuristic == AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation && quantitativeResult) {
277 score = score * (quantitativeResult.get().max.values - quantitativeResult.get().min.values);
278 }
279 selectedPivotState = score.maxAbstractRepresentative(game.getRowVariables());
280 STORM_LOG_TRACE("Selected pivot state with score " << score.getMax() << ".");
281
282 storm::OptimizationDirection fromDirection = storm::OptimizationDirection::Minimize;
283 storm::dd::Add<Type, ValueType> selectedPivotStateAsAdd = selectedPivotState.template toAdd<ValueType>();
284 if ((selectedPivotStateAsAdd * maxSymbolicMostProbablePathsResult.maxProbabilities).getMax() >
285 (selectedPivotStateAsAdd * minSymbolicMostProbablePathsResult.maxProbabilities).getMax()) {
286 fromDirection = storm::OptimizationDirection::Maximize;
287 }
288
290 selectedPivotState, fromDirection,
291 fromDirection == storm::OptimizationDirection::Minimize ? minSymbolicMostProbablePathsResult : maxSymbolicMostProbablePathsResult);
292 }
293
294 STORM_LOG_ASSERT(false, "This point must not be reached, because then no pivot state could be found.");
295 return SymbolicPivotStateResult<Type, ValueType>(storm::dd::Bdd<Type>(), storm::OptimizationDirection::Minimize);
296}
297
298template<storm::dd::DdType Type, typename ValueType>
299RefinementPredicates MenuGameRefiner<Type, ValueType>::derivePredicatesFromDifferingChoices(storm::dd::Bdd<Type> const& player1Choice,
300 storm::dd::Bdd<Type> const& lowerChoice,
301 storm::dd::Bdd<Type> const& upperChoice) const {
302 // Prepare result.
304 bool fromGuard = false;
305
306 // Get abstraction information for easier access.
307 AbstractionInformation<Type> const& abstractionInformation = abstractor.get().getAbstractionInformation();
308
309 // Decode the index of the command chosen by player 1.
310 storm::dd::Add<Type, ValueType> player1ChoiceAsAdd = player1Choice.template toAdd<ValueType>();
311 auto pl1It = player1ChoiceAsAdd.begin();
312 uint_fast64_t player1Index = abstractionInformation.decodePlayer1Choice((*pl1It).first, abstractionInformation.getPlayer1VariableCount());
313
314 // Check whether there are bottom states in the game and whether one of the choices actually picks the
315 // bottom state as the successor.
316 bool buttomStateSuccessor =
317 !((abstractionInformation.getBottomStateBdd(false, false) && lowerChoice) || (abstractionInformation.getBottomStateBdd(false, false) && upperChoice))
318 .isZero();
319
320 // If one of the choices picks the bottom state, the new predicate is based on the guard of the appropriate
321 // command (that is the player 1 choice).
322 if (buttomStateSuccessor) {
323 STORM_LOG_TRACE("One of the successors is a bottom state, taking a guard as a new predicate.");
324 newPredicate = abstractor.get().getGuard(player1Index);
325 fromGuard = true;
326 STORM_LOG_DEBUG("Derived new predicate (based on guard): " << newPredicate);
327 } else {
328 STORM_LOG_TRACE("No bottom state successor. Deriving a new predicate using weakest precondition.");
329
330 // Decode both choices to explicit mappings.
331 std::map<uint64_t, std::pair<storm::storage::BitVector, ValueType>> lowerChoiceUpdateToSuccessorMapping =
332 abstractionInformation.template decodeChoiceToUpdateSuccessorMapping<ValueType>(lowerChoice);
333 std::map<uint64_t, std::pair<storm::storage::BitVector, ValueType>> upperChoiceUpdateToSuccessorMapping =
334 abstractionInformation.template decodeChoiceToUpdateSuccessorMapping<ValueType>(upperChoice);
336 lowerChoiceUpdateToSuccessorMapping.size() == upperChoiceUpdateToSuccessorMapping.size(),
337 "Mismatching sizes after decode (" << lowerChoiceUpdateToSuccessorMapping.size() << " vs. " << upperChoiceUpdateToSuccessorMapping.size() << ").");
338
339 // First, sort updates according to probability mass.
340 std::vector<std::pair<uint64_t, ValueType>> updateIndicesAndMasses;
341 for (auto const& entry : lowerChoiceUpdateToSuccessorMapping) {
342 updateIndicesAndMasses.emplace_back(entry.first, entry.second.second);
343 }
344 std::sort(updateIndicesAndMasses.begin(), updateIndicesAndMasses.end(),
345 [](std::pair<uint64_t, ValueType> const& a, std::pair<uint64_t, ValueType> const& b) { return a.second > b.second; });
346
347 // Now find the update with the highest probability mass among all deviating updates. More specifically,
348 // we determine the set of predicate indices for which there is a deviation.
349 std::set<uint64_t> deviationPredicates;
350 uint64_t orderedUpdateIndex = 0;
351 std::vector<storm::expressions::Expression> possibleRefinementPredicates;
352 for (; orderedUpdateIndex < updateIndicesAndMasses.size(); ++orderedUpdateIndex) {
353 storm::storage::BitVector const& lower = lowerChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first;
354 storm::storage::BitVector const& upper = upperChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first;
355
356 bool deviates = lower != upper;
357 if (deviates) {
358 std::map<storm::expressions::Variable, storm::expressions::Expression> variableUpdates =
359 abstractor.get().getVariableUpdates(player1Index, updateIndicesAndMasses[orderedUpdateIndex].first);
360
361 for (uint64_t predicateIndex = 0; predicateIndex < lower.size(); ++predicateIndex) {
362 if (lower[predicateIndex] != upper[predicateIndex]) {
363 possibleRefinementPredicates.push_back(
364 abstractionInformation.getPredicateByIndex(predicateIndex).substitute(variableUpdates).simplify());
365 if (!rankPredicates) {
366 break;
367 }
368 }
369 }
370 break;
371 }
372 }
373
374 STORM_LOG_ASSERT(!possibleRefinementPredicates.empty(), "Expected refinement predicates.");
375
376 STORM_LOG_TRACE("Possible refinement predicates:");
377 for (auto const& pred : possibleRefinementPredicates) {
378 STORM_LOG_TRACE(pred);
379 }
380
381 if (rankPredicates) {
382 // Since we can choose any of the deviation predicates to perform the split, we go through the remaining
383 // updates and build all deviation predicates. We can then check whether any of the possible refinement
384 // predicates also eliminates another deviation.
385 std::vector<storm::expressions::Expression> otherRefinementPredicates;
386 for (; orderedUpdateIndex < updateIndicesAndMasses.size(); ++orderedUpdateIndex) {
387 storm::storage::BitVector const& lower = lowerChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first;
388 storm::storage::BitVector const& upper = upperChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first;
389
390 bool deviates = lower != upper;
391 if (deviates) {
392 std::map<storm::expressions::Variable, storm::expressions::Expression> newVariableUpdates =
393 abstractor.get().getVariableUpdates(player1Index, updateIndicesAndMasses[orderedUpdateIndex].first);
394 for (uint64_t predicateIndex = 0; predicateIndex < lower.size(); ++predicateIndex) {
395 if (lower[predicateIndex] != upper[predicateIndex]) {
396 otherRefinementPredicates.push_back(
397 abstractionInformation.getPredicateByIndex(predicateIndex).substitute(newVariableUpdates).simplify());
398 }
399 }
400 }
401 }
402
403 // Finally, go through the refinement predicates and see how many deviations they cover.
404 std::vector<uint64_t> refinementPredicateIndexToCount(possibleRefinementPredicates.size(), 0);
405 for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) {
406 refinementPredicateIndexToCount[index] = 1;
407 }
408 for (auto const& otherPredicate : otherRefinementPredicates) {
409 for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) {
410 if (equivalenceChecker.areEquivalentModuloNegation(otherPredicate, possibleRefinementPredicates[index])) {
411 ++refinementPredicateIndexToCount[index];
412 }
413 }
414 }
415
416 // Find predicate that covers the most deviations.
417 uint64_t chosenPredicateIndex = 0;
418 for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) {
419 if (refinementPredicateIndexToCount[index] > refinementPredicateIndexToCount[chosenPredicateIndex]) {
420 chosenPredicateIndex = index;
421 }
422 }
423 newPredicate = possibleRefinementPredicates[chosenPredicateIndex];
424 STORM_LOG_DEBUG("Derived new predicate (based on weakest-precondition): " << newPredicate << ", (equivalent to "
425 << (refinementPredicateIndexToCount[chosenPredicateIndex] - 1)
426 << " other refinement predicates).");
427 } else {
428 newPredicate = possibleRefinementPredicates.front();
429 STORM_LOG_DEBUG("Derived new predicate (based on weakest-precondition): " << newPredicate << ".");
430 }
431
432 STORM_LOG_ASSERT(newPredicate.isInitialized(), "Could not derive new predicate as there is no deviation.");
433 }
434
435 return RefinementPredicates(fromGuard ? RefinementPredicates::Source::Guard : RefinementPredicates::Source::WeakestPrecondition, {newPredicate});
436}
437
438template<storm::dd::DdType Type, typename ValueType>
439RefinementPredicates MenuGameRefiner<Type, ValueType>::derivePredicatesFromChoice(storm::gbar::abstraction::MenuGame<Type, ValueType> const& game,
440 storm::dd::Bdd<Type> const& pivotState,
441 storm::dd::Bdd<Type> const& player1Choice, storm::dd::Bdd<Type> const& choice,
442 storm::dd::Bdd<Type> const& choiceSuccessors) const {
443 // Prepare result.
445 bool fromGuard = false;
446
447 // Get abstraction information for easier access.
448 AbstractionInformation<Type> const& abstractionInformation = abstractor.get().getAbstractionInformation();
449
450 // Decode the index of the command chosen by player 1.
451 storm::dd::Add<Type, ValueType> player1ChoiceAsAdd = player1Choice.template toAdd<ValueType>();
452 auto pl1It = player1ChoiceAsAdd.begin();
453 uint_fast64_t player1Index = abstractionInformation.decodePlayer1Choice((*pl1It).first, abstractionInformation.getPlayer1VariableCount());
454
455 // Check whether there are bottom states in the game and whether the choice actually picks the bottom state
456 // as the successor.
457 bool buttomStateSuccessor = !((abstractionInformation.getBottomStateBdd(false, false) && choiceSuccessors)).isZero();
458
459 std::vector<storm::expressions::Expression> possibleRefinementPredicates;
460
461 // If the choice picks the bottom state, the new predicate is based on the guard of the appropriate command
462 // (that is the player 1 choice).
463 if (buttomStateSuccessor) {
464 STORM_LOG_TRACE("One of the successors is a bottom state, taking a guard as a new predicate.");
465 possibleRefinementPredicates.emplace_back(abstractor.get().getGuard(player1Index));
466 fromGuard = true;
467 STORM_LOG_DEBUG("Derived new predicate (based on guard): " << possibleRefinementPredicates.back());
468 } else {
469 STORM_LOG_TRACE("No bottom state successor. Deriving a new predicate using weakest precondition.");
470
471 // Decode the choice successors.
472 std::map<uint64_t, std::pair<storm::storage::BitVector, ValueType>> choiceUpdateToSuccessorMapping =
473 abstractionInformation.template decodeChoiceToUpdateSuccessorMapping<ValueType>(choiceSuccessors);
474 std::vector<std::pair<uint64_t, ValueType>> sortedChoiceUpdateIndicesAndMasses;
475 for (auto const& e : choiceUpdateToSuccessorMapping) {
476 sortedChoiceUpdateIndicesAndMasses.emplace_back(e.first, e.second.second);
477 }
478 std::sort(sortedChoiceUpdateIndicesAndMasses.begin(), sortedChoiceUpdateIndicesAndMasses.end(),
479 [](std::pair<uint64_t, ValueType> const& a, std::pair<uint64_t, ValueType> const& b) { return a.second > b.second; });
480
481 // Compute all other (not taken) choices.
482 std::set<storm::expressions::Variable> variablesToAbstract = game.getRowVariables();
483 variablesToAbstract.insert(game.getPlayer1Variables().begin(), game.getPlayer1Variables().end());
484
485 storm::dd::Bdd<Type> otherChoices =
486 (pivotState && !choice && player1Choice && game.getExtendedTransitionMatrix().toBdd()).existsAbstract(variablesToAbstract);
487 STORM_LOG_ASSERT(!otherChoices.isZero(), "Expected other choices.");
488
489 // Decode the other choices.
490 std::vector<std::map<uint64_t, std::pair<storm::storage::BitVector, ValueType>>> otherChoicesUpdateToSuccessorMappings =
491 abstractionInformation.template decodeChoicesToUpdateSuccessorMapping<ValueType>(game.getPlayer2Variables(), otherChoices);
492
493 for (auto const& otherChoice : otherChoicesUpdateToSuccessorMappings) {
494 for (uint64_t updateIndex = 0; updateIndex < sortedChoiceUpdateIndicesAndMasses.size(); ++updateIndex) {
495 storm::storage::BitVector const& choiceSuccessor =
496 choiceUpdateToSuccessorMapping.at(sortedChoiceUpdateIndicesAndMasses[updateIndex].first).first;
497 storm::storage::BitVector const& otherChoiceSuccessor = otherChoice.at(sortedChoiceUpdateIndicesAndMasses[updateIndex].first).first;
498
499 bool deviates = choiceSuccessor != otherChoiceSuccessor;
500 if (deviates) {
501 std::map<storm::expressions::Variable, storm::expressions::Expression> variableUpdates =
502 abstractor.get().getVariableUpdates(player1Index, sortedChoiceUpdateIndicesAndMasses[updateIndex].first);
503
504 for (uint64_t predicateIndex = 0; predicateIndex < choiceSuccessor.size(); ++predicateIndex) {
505 if (choiceSuccessor[predicateIndex] != otherChoiceSuccessor[predicateIndex]) {
506 possibleRefinementPredicates.push_back(
507 abstractionInformation.getPredicateByIndex(predicateIndex).substitute(variableUpdates).simplify());
508 if (!rankPredicates) {
509 break;
510 }
511 }
512 }
513
514 break;
515 }
516 }
517 }
518
519 STORM_LOG_ASSERT(!possibleRefinementPredicates.empty(), "Expected refinement predicates.");
520
521 STORM_LOG_TRACE("Possible refinement predicates:");
522 for (auto const& pred : possibleRefinementPredicates) {
523 STORM_LOG_TRACE(pred);
524 }
525 }
526
527 return RefinementPredicates(fromGuard ? RefinementPredicates::Source::Guard : RefinementPredicates::Source::WeakestPrecondition,
528 {possibleRefinementPredicates});
529}
530
531template<storm::dd::DdType Type, typename ValueType>
533 storm::dd::Bdd<Type> const& transitionMatrixBdd, storm::dd::Bdd<Type> const& minPlayer1Strategy,
534 storm::dd::Bdd<Type> const& minPlayer2Strategy, storm::dd::Bdd<Type> const& maxPlayer1Strategy,
535 storm::dd::Bdd<Type> const& maxPlayer2Strategy) {
537
538 // Build the fragment of transitions that is reachable by either the min or the max strategies.
539 result.reachableTransitionsMin = (transitionMatrixBdd && minPlayer1Strategy && minPlayer2Strategy).existsAbstract(game.getNondeterminismVariables());
540 result.reachableTransitionsMax = (transitionMatrixBdd && maxPlayer1Strategy && maxPlayer2Strategy).existsAbstract(game.getNondeterminismVariables());
541
542 // Start with all reachable states as potential pivot states.
543 result.pivotStates =
545 .first ||
547 .first;
548
549 // Then constrain these states by the requirement that for either the lower or upper player 1 choice the player 2 choices must be different and
550 // that the difference is not because of a missing strategy in either case.
551
552 // Start with constructing the player 2 states that have a min and a max strategy.
553 storm::dd::Bdd<Type> constraint =
554 minPlayer2Strategy.existsAbstract(game.getPlayer2Variables()) && maxPlayer2Strategy.existsAbstract(game.getPlayer2Variables());
555
556 // Now construct all player 2 choices that actually exist and differ in the min and max case.
557 constraint &= minPlayer2Strategy.exclusiveOr(maxPlayer2Strategy);
558
559 // Then restrict the pivot states by requiring existing and different player 2 choices.
560 result.pivotStates &= ((minPlayer1Strategy || maxPlayer1Strategy) && constraint).existsAbstract(game.getNondeterminismVariables());
561
562 return result;
563}
564
565template<storm::dd::DdType Type, typename ValueType>
566RefinementPredicates MenuGameRefiner<Type, ValueType>::derivePredicatesFromPivotState(
567 storm::gbar::abstraction::MenuGame<Type, ValueType> const& game, storm::dd::Bdd<Type> const& pivotState, storm::dd::Bdd<Type> const& minPlayer1Strategy,
568 storm::dd::Bdd<Type> const& minPlayer2Strategy, storm::dd::Bdd<Type> const& maxPlayer1Strategy, storm::dd::Bdd<Type> const& maxPlayer2Strategy) const {
569 // Compute the lower and the upper choice for the pivot state.
570 std::set<storm::expressions::Variable> variablesToAbstract = game.getNondeterminismVariables();
571 variablesToAbstract.insert(game.getRowVariables().begin(), game.getRowVariables().end());
572
573 bool player1ChoicesDifferent = !(pivotState && minPlayer1Strategy).exclusiveOr(pivotState && maxPlayer1Strategy).isZero();
574
575 boost::optional<RefinementPredicates> predicates;
576
577 // Derive predicates from lower choice.
578 storm::dd::Bdd<Type> lowerChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && minPlayer1Strategy;
579 storm::dd::Bdd<Type> lowerChoice1 = (lowerChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract);
580 storm::dd::Bdd<Type> lowerChoice2 = (lowerChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract);
581
582 bool lowerChoicesDifferent = !lowerChoice1.exclusiveOr(lowerChoice2).isZero() && !lowerChoice1.isZero() && !lowerChoice2.isZero();
583 if (lowerChoicesDifferent) {
584 STORM_LOG_TRACE("Deriving predicates based on lower choice.");
585 if (this->addPredicatesEagerly) {
586 predicates = derivePredicatesFromChoice(game, pivotState, (pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()),
587 lowerChoice && minPlayer2Strategy, lowerChoice1);
588 } else {
589 predicates =
590 derivePredicatesFromDifferingChoices((pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()), lowerChoice1, lowerChoice2);
591 }
592 }
593
594 if (predicates && !player1ChoicesDifferent) {
595 return predicates.get();
596 }
597
598 boost::optional<RefinementPredicates> additionalPredicates;
599
600 storm::dd::Bdd<Type> upperChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && maxPlayer1Strategy;
601 storm::dd::Bdd<Type> upperChoice1 = (upperChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract);
602 storm::dd::Bdd<Type> upperChoice2 = (upperChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract);
603
604 bool upperChoicesDifferent = !upperChoice1.exclusiveOr(upperChoice2).isZero() && !upperChoice1.isZero() && !upperChoice2.isZero();
605 if (upperChoicesDifferent) {
606 STORM_LOG_TRACE("Deriving predicates based on upper choice.");
607 if (this->addPredicatesEagerly) {
608 additionalPredicates = derivePredicatesFromChoice(game, pivotState, (pivotState && maxPlayer1Strategy).existsAbstract(game.getRowVariables()),
609 upperChoice && maxPlayer2Strategy, upperChoice1);
610 } else {
611 additionalPredicates =
612 derivePredicatesFromDifferingChoices((pivotState && maxPlayer1Strategy).existsAbstract(game.getRowVariables()), upperChoice1, upperChoice2);
613 }
614 }
615
616 if (additionalPredicates) {
617 if (additionalPredicates.get().getSource() == RefinementPredicates::Source::Guard) {
618 return additionalPredicates.get();
619 } else {
620 if (!predicates) {
621 predicates = additionalPredicates;
622 } else {
623 predicates.get().addPredicates(additionalPredicates.get().getPredicates());
624 }
625 }
626 }
627
628 STORM_LOG_THROW(static_cast<bool>(predicates), storm::exceptions::InvalidStateException, "Could not derive predicates for refinement.");
629
630 return predicates.get();
631}
632
633template<storm::dd::DdType Type, typename ValueType>
634std::pair<std::vector<std::vector<storm::expressions::Expression>>, std::map<storm::expressions::Variable, storm::expressions::Expression>>
635MenuGameRefiner<Type, ValueType>::buildTrace(storm::expressions::ExpressionManager& expressionManager,
637 storm::dd::Bdd<Type> const& pivotState) const {
638 std::vector<std::vector<storm::expressions::Expression>> predicates;
639
640 // Prepare some variables.
641 AbstractionInformation<Type> const& abstractionInformation = abstractor.get().getAbstractionInformation();
642 std::set<storm::expressions::Variable> variablesToAbstract(game.getColumnVariables());
643 variablesToAbstract.insert(game.getPlayer1Variables().begin(), game.getPlayer1Variables().end());
644 variablesToAbstract.insert(game.getProbabilisticBranchingVariables().begin(), game.getProbabilisticBranchingVariables().end());
645
646 storm::expressions::Expression initialExpression = abstractor.get().getInitialExpression();
647
648 std::set<storm::expressions::Variable> oldVariables = initialExpression.getVariables();
649 for (auto const& predicate : abstractionInformation.getPredicates()) {
650 std::set<storm::expressions::Variable> usedVariables = predicate.getVariables();
651 oldVariables.insert(usedVariables.begin(), usedVariables.end());
652 }
653
654 std::map<storm::expressions::Variable, storm::expressions::Variable> oldToNewVariables;
655 for (auto const& variable : oldVariables) {
656 oldToNewVariables[variable] = expressionManager.getVariable(variable.getName());
657 }
658 std::map<storm::expressions::Variable, storm::expressions::Expression> lastSubstitution;
659 for (auto const& variable : oldToNewVariables) {
660 lastSubstitution[variable.second] = variable.second;
661 }
662 std::map<storm::expressions::Variable, storm::expressions::Expression> stepVariableToCopiedVariableMap;
663
664 // Start with the target state part of the trace.
665 storm::storage::BitVector decodedTargetState = abstractionInformation.decodeState(pivotState);
666 predicates.emplace_back(abstractionInformation.getPredicates(decodedTargetState));
667 for (auto& predicate : predicates.back()) {
668 predicate = predicate.changeManager(expressionManager);
669 }
670 // Add ranges of variables.
671 for (auto const& pred : abstractionInformation.getConstraints()) {
672 predicates.back().push_back(pred.changeManager(expressionManager));
673 }
674
675 // Perform a backward search for an initial state.
676 storm::dd::Bdd<Type> currentState = pivotState;
677 while ((currentState && game.getInitialStates()).isZero()) {
678 storm::dd::Bdd<Type> predecessorTransition = currentState.swapVariables(game.getRowColumnMetaVariablePairs()) && spanningTree;
679 std::tuple<storm::storage::BitVector, uint64_t, uint64_t> decodedPredecessor =
680 abstractionInformation.decodeStatePlayer1ChoiceAndUpdate(predecessorTransition);
681
682 // Create a new copy of each variable to use for this step.
683 std::map<storm::expressions::Variable, storm::expressions::Expression> substitution;
684 for (auto const& variablePair : oldToNewVariables) {
685 storm::expressions::Variable variableCopy = expressionManager.declareVariableCopy(variablePair.second);
686 substitution[variablePair.second] = variableCopy;
687 stepVariableToCopiedVariableMap[variableCopy] = variablePair.second;
688 }
689
690 // Retrieve the variable updates that the predecessor needs to perform to get to the current state.
691 auto variableUpdates = abstractor.get().getVariableUpdates(std::get<1>(decodedPredecessor), std::get<2>(decodedPredecessor));
692 for (auto const& oldNewVariablePair : oldToNewVariables) {
693 storm::expressions::Variable const& newVariable = oldNewVariablePair.second;
694
695 // If the variable was set, use its update expression.
696 auto updateIt = variableUpdates.find(oldNewVariablePair.first);
697 if (updateIt != variableUpdates.end()) {
698 auto const& update = *updateIt;
699
700 if (update.second.hasBooleanType()) {
701 predicates.back().push_back(
702 storm::expressions::iff(lastSubstitution.at(newVariable), update.second.changeManager(expressionManager).substitute(substitution)));
703 } else {
704 predicates.back().push_back(lastSubstitution.at(newVariable) == update.second.changeManager(expressionManager).substitute(substitution));
705 }
706 } else {
707 // Otherwise, make sure that the new variable maintains the old value.
708 if (newVariable.hasBooleanType()) {
709 predicates.back().push_back(storm::expressions::iff(lastSubstitution.at(newVariable), substitution.at(newVariable)));
710 } else {
711 predicates.back().push_back(lastSubstitution.at(newVariable) == substitution.at(newVariable));
712 }
713 }
714 }
715
716 // Add the guard of the choice.
717 predicates.back().push_back(abstractor.get().getGuard(std::get<1>(decodedPredecessor)).changeManager(expressionManager).substitute(substitution));
718
719 // Retrieve the predicate valuation in the predecessor.
720 predicates.emplace_back(abstractionInformation.getPredicates(std::get<0>(decodedPredecessor)));
721 for (auto& predicate : predicates.back()) {
722 predicate = predicate.changeManager(expressionManager).substitute(substitution);
723 }
724 // Add ranges of variables.
725 for (auto const& pred : abstractionInformation.getConstraints()) {
726 predicates.back().push_back(pred.changeManager(expressionManager).substitute(substitution));
727 }
728 // Move backwards one step.
729 lastSubstitution = std::move(substitution);
730 currentState = predecessorTransition.existsAbstract(variablesToAbstract);
731 }
732
733 predicates.back().push_back(initialExpression.changeManager(expressionManager).substitute(lastSubstitution));
734 return std::make_pair(predicates, stepVariableToCopiedVariableMap);
735}
736
737template<typename ValueType>
738const uint64_t ExplicitPivotStateResult<ValueType>::NO_PREDECESSOR = std::numeric_limits<uint64_t>::max();
739
740template<storm::dd::DdType Type, typename ValueType>
741std::pair<std::vector<uint64_t>, std::vector<uint64_t>> MenuGameRefiner<Type, ValueType>::buildReversedLabeledPath(
742 ExplicitPivotStateResult<ValueType> const& pivotStateResult) const {
743 std::pair<std::vector<uint64_t>, std::vector<uint64_t>> result;
744 result.first.emplace_back(pivotStateResult.pivotState);
745
746 uint64_t currentState = pivotStateResult.predecessors[pivotStateResult.pivotState].first;
747 uint64_t currentAction = pivotStateResult.predecessors[pivotStateResult.pivotState].second;
749 STORM_LOG_ASSERT(currentAction != ExplicitPivotStateResult<ValueType>::NO_PREDECESSOR, "Expected predecessor action.");
750 result.first.emplace_back(currentState);
751 result.second.emplace_back(currentAction);
752 currentAction = pivotStateResult.predecessors[currentState].second;
753 currentState = pivotStateResult.predecessors[currentState].first;
754 }
755
756 STORM_LOG_ASSERT(result.first.size() == result.second.size() + 1, "Path size mismatch.");
757 return result;
758}
759
760template<storm::dd::DdType Type, typename ValueType>
761std::pair<std::vector<std::vector<storm::expressions::Expression>>, std::map<storm::expressions::Variable, storm::expressions::Expression>>
762MenuGameRefiner<Type, ValueType>::buildTraceFromReversedLabeledPath(storm::expressions::ExpressionManager& expressionManager,
763 std::vector<uint64_t> const& reversedPath, std::vector<uint64_t> const& reversedLabels,
764 storm::dd::Odd const& odd, std::vector<uint64_t> const* stateToOffset) const {
765 STORM_LOG_ASSERT(reversedPath.size() == reversedLabels.size() + 1, "Path size mismatch.");
766
767 std::vector<std::vector<storm::expressions::Expression>> predicates;
768
769 AbstractionInformation<Type> const& abstractionInformation = abstractor.get().getAbstractionInformation();
770 storm::expressions::Expression initialExpression = abstractor.get().getInitialExpression();
771
772 std::set<storm::expressions::Variable> oldVariables = initialExpression.getVariables();
773 for (auto const& predicate : abstractionInformation.getPredicates()) {
774 std::set<storm::expressions::Variable> usedVariables = predicate.getVariables();
775 oldVariables.insert(usedVariables.begin(), usedVariables.end());
776 }
777
778 std::map<storm::expressions::Variable, storm::expressions::Variable> oldToNewVariables;
779 for (auto const& variable : oldVariables) {
780 oldToNewVariables[variable] = expressionManager.getVariable(variable.getName());
781 }
782 std::map<storm::expressions::Variable, storm::expressions::Expression> currentSubstitution;
783 for (auto const& variable : oldToNewVariables) {
784 currentSubstitution[variable.second] = variable.second;
785 }
786 std::map<storm::expressions::Variable, storm::expressions::Expression> stepVariableToCopiedVariableMap;
787
788 auto pathIt = reversedPath.rbegin();
789
790 // Decode pivot state. The state valuation also includes
791 // * the bottom state, so we need to reserve one more, and
792 // * the location variables,
793 // so we need to reserve an appropriate size.
794 uint64_t predicateValuationOffset = abstractionInformation.getNumberOfDdSourceLocationVariables() + 1;
795 storm::storage::BitVector extendedPredicateValuation =
796 odd.getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + predicateValuationOffset);
797 ++pathIt;
798
799 // Add all predicates of initial block.
800 predicates.emplace_back(abstractionInformation.getPredicatesExcludingBottom(extendedPredicateValuation));
801 for (auto& predicate : predicates.back()) {
802 predicate = predicate.changeManager(expressionManager);
803 }
804
805 // Add further constraints (like ranges).
806 for (auto const& pred : abstractionInformation.getConstraints()) {
807 predicates.back().push_back(pred.changeManager(expressionManager));
808 }
809
810 // Add initial expression.
811 predicates.back().push_back(initialExpression.changeManager(expressionManager));
812
813 // Traverse the path and construct necessary formula parts.
814 auto actionIt = reversedLabels.rbegin();
815 for (; pathIt != reversedPath.rend(); ++pathIt) {
816 // Add new predicate frame.
817 predicates.emplace_back();
818
819 // Add guard of action.
820 predicates.back().emplace_back(abstractor.get().getGuard(*actionIt).changeManager(expressionManager).substitute(currentSubstitution));
821
822 // Determine which variables are affected by the updates of the player 1 choice.
823 std::set<storm::expressions::Variable> const& assignedVariables = abstractor.get().getAssignedVariables(*actionIt);
824
825 // Create new instances of the affected variables.
826 std::map<storm::expressions::Variable, storm::expressions::Variable> newVariableMaps;
827 for (auto const& variable : assignedVariables) {
828 storm::expressions::Variable variableCopy = expressionManager.declareVariableCopy(variable);
829 newVariableMaps[oldToNewVariables.at(variable)] = variableCopy;
830 stepVariableToCopiedVariableMap[variableCopy] = variable;
831 }
832
833 // Retrieves the possible updates to the variables.
834 auto variableUpdateVector = abstractor.get().getVariableUpdates(*actionIt);
835
836 // Encode these updates.
837 storm::expressions::Expression allVariableUpdateExpression;
838 for (auto const& variableUpdates : variableUpdateVector) {
839 storm::expressions::Expression variableUpdateExpression;
840 for (auto const& update : variableUpdates) {
841 if (update.second.hasBooleanType()) {
842 variableUpdateExpression =
843 variableUpdateExpression && storm::expressions::iff(newVariableMaps.at(update.first),
844 update.second.changeManager(expressionManager).substitute(currentSubstitution));
845 } else {
846 variableUpdateExpression = variableUpdateExpression && newVariableMaps.at(update.first) ==
847 update.second.changeManager(expressionManager).substitute(currentSubstitution);
848 }
849 }
850
851 allVariableUpdateExpression = allVariableUpdateExpression || variableUpdateExpression;
852 }
853 if (!allVariableUpdateExpression.isInitialized()) {
854 allVariableUpdateExpression = expressionManager.boolean(true);
855 }
856 predicates.back().emplace_back(allVariableUpdateExpression);
857
858 // Incorporate the new variables in the current substitution.
859 for (auto const& variablePair : newVariableMaps) {
860 currentSubstitution[variablePair.first] = variablePair.second;
861 }
862
863 // Decode current state.
864 extendedPredicateValuation =
865 odd.getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + predicateValuationOffset);
866
867 // Encode the predicates whose value might have changed.
868 // FIXME: could be optimized by precomputation.
869 for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.getNumberOfPredicates(); ++predicateIndex) {
870 auto const& predicate = abstractionInformation.getPredicateByIndex(predicateIndex);
871 std::set<storm::expressions::Variable> usedVariables = predicate.getVariables();
872
873 bool containsAssignedVariables = false;
874 for (auto usedIt = usedVariables.begin(), assignedIt = assignedVariables.begin();;) {
875 if (usedIt == usedVariables.end() || assignedIt == assignedVariables.end()) {
876 break;
877 }
878
879 if (*usedIt == *assignedIt) {
880 containsAssignedVariables = true;
881 break;
882 }
883
884 if (*usedIt < *assignedIt) {
885 ++usedIt;
886 } else {
887 ++assignedIt;
888 }
889 }
890
891 if (containsAssignedVariables) {
892 auto transformedPredicate = predicate.changeManager(expressionManager).substitute(currentSubstitution);
893 predicates.back().emplace_back(extendedPredicateValuation.get(predicateIndex + predicateValuationOffset) ? transformedPredicate
894 : !transformedPredicate);
895 }
896 }
897
898 // Enforce constraints of all assigned variables.
899 for (auto const& constraint : abstractionInformation.getConstraints()) {
900 std::set<storm::expressions::Variable> usedVariables = constraint.getVariables();
901
902 bool containsAssignedVariables = false;
903 for (auto usedIt = usedVariables.begin(), assignedIt = assignedVariables.begin();;) {
904 if (usedIt == usedVariables.end() || assignedIt == assignedVariables.end()) {
905 break;
906 }
907
908 if (*usedIt == *assignedIt) {
909 containsAssignedVariables = true;
910 break;
911 }
912
913 if (*usedIt < *assignedIt) {
914 ++usedIt;
915 } else {
916 ++assignedIt;
917 }
918 }
919
920 if (containsAssignedVariables) {
921 auto transformedConstraint = constraint.changeManager(expressionManager).substitute(currentSubstitution);
922 predicates.back().emplace_back(transformedConstraint);
923 }
924 }
925
926 ++actionIt;
927 }
928
929 return std::make_pair(predicates, stepVariableToCopiedVariableMap);
930}
931
932template<storm::dd::DdType Type, typename ValueType>
933boost::optional<RefinementPredicates> MenuGameRefiner<Type, ValueType>::derivePredicatesFromInterpolationFromTrace(
934 storm::expressions::ExpressionManager& interpolationManager, std::vector<std::vector<storm::expressions::Expression>> const& trace,
935 std::map<storm::expressions::Variable, storm::expressions::Expression> const& variableSubstitution) const {
936 AbstractionInformation<Type> const& abstractionInformation = abstractor.get().getAbstractionInformation();
937
938 auto start = std::chrono::high_resolution_clock::now();
939 boost::optional<RefinementPredicates> predicates;
940
941 // Create solver and interpolation groups.
942 auto assertionStart = std::chrono::high_resolution_clock::now();
943 storm::solver::MathsatSmtSolver interpolatingSolver(interpolationManager, storm::solver::MathsatSmtSolver::Options(true, false, true));
944 uint64_t stepCounter = 0;
945 for (auto const& traceElement : trace) {
946 // interpolatingSolver.push();
947
948 interpolatingSolver.setInterpolationGroup(stepCounter);
949 for (auto const& predicate : traceElement) {
950 interpolatingSolver.add(predicate);
951 }
952
953 ++stepCounter;
954 }
955 auto assertionEnd = std::chrono::high_resolution_clock::now();
956 STORM_LOG_TRACE("Asserting trace formula took " << std::chrono::duration_cast<std::chrono::milliseconds>(assertionEnd - assertionStart).count() << "ms.");
957
958 // Now encode the trace as an SMT problem.
959 storm::solver::SmtSolver::CheckResult result = interpolatingSolver.check();
961 STORM_LOG_TRACE("Trace formula is unsatisfiable. Starting interpolation.");
962
963 std::vector<storm::expressions::Expression> interpolants;
964 std::vector<uint64_t> prefix;
965 for (uint64_t step = 0; step < stepCounter; ++step) {
966 prefix.push_back(step);
968 interpolatingSolver.getInterpolant(prefix).substitute(variableSubstitution).changeManager(abstractionInformation.getExpressionManager());
969 if (interpolant.isFalse()) {
970 // If the interpolant is false, it means that the prefix has become unsatisfiable.
971 STORM_LOG_TRACE("Trace formula became unsatisfiable at position " << step << " of " << stepCounter << ".");
972 break;
973 }
974 if (!interpolant.isTrue()) {
975 STORM_LOG_DEBUG("Derived new predicate (based on interpolation at step " << step << " out of " << stepCounter << "): " << interpolant);
976 interpolants.push_back(interpolant);
977 }
978 }
979
980 STORM_LOG_ASSERT(!interpolants.empty(), "Expected to have non-empty set of interpolants.");
981
982 predicates = boost::make_optional(RefinementPredicates(RefinementPredicates::Source::Interpolation, interpolants));
983 } else {
984 STORM_LOG_TRACE("Trace formula is satisfiable, not using interpolation.");
985 }
986 auto end = std::chrono::high_resolution_clock::now();
987
988 if (predicates) {
989 STORM_LOG_TRACE("Deriving predicates using interpolation from witness of size "
990 << trace.size() << " took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
991 } else {
992 STORM_LOG_TRACE("Tried deriving predicates using interpolation but failed in "
993 << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
994 }
995
996 return predicates;
997}
998
999template<storm::dd::DdType Type, typename ValueType>
1000boost::optional<RefinementPredicates> MenuGameRefiner<Type, ValueType>::derivePredicatesFromInterpolation(
1001 storm::gbar::abstraction::MenuGame<Type, ValueType> const& game, SymbolicPivotStateResult<Type, ValueType> const& symbolicPivotStateResult,
1002 storm::dd::Bdd<Type> const& minPlayer1Strategy, storm::dd::Bdd<Type> const& minPlayer2Strategy, storm::dd::Bdd<Type> const& maxPlayer1Strategy,
1003 storm::dd::Bdd<Type> const& maxPlayer2Strategy) const {
1004 // Compute the most probable path from any initial state to the pivot state.
1005 SymbolicMostProbablePathsResult<Type, ValueType> symbolicMostProbablePathsResult;
1006 if (!symbolicPivotStateResult.symbolicMostProbablePathsResult) {
1007 symbolicMostProbablePathsResult = getMostProbablePathSpanningTree(game, symbolicPivotStateResult.fromDirection == storm::OptimizationDirection::Minimize
1008 ? minPlayer1Strategy && minPlayer2Strategy
1009 : maxPlayer1Strategy && maxPlayer2Strategy);
1010 } else {
1011 symbolicMostProbablePathsResult = symbolicPivotStateResult.symbolicMostProbablePathsResult.get();
1012 }
1013
1014 // Create a new expression manager that we can use for the interpolation.
1015 AbstractionInformation<Type> const& abstractionInformation = abstractor.get().getAbstractionInformation();
1016 std::shared_ptr<storm::expressions::ExpressionManager> interpolationManager = abstractionInformation.getExpressionManager().clone();
1017
1018 // Build the trace of the most probable path in terms of which predicates hold in each step.
1019 auto start = std::chrono::high_resolution_clock::now();
1020 std::pair<std::vector<std::vector<storm::expressions::Expression>>, std::map<storm::expressions::Variable, storm::expressions::Expression>>
1021 traceAndVariableSubstitution =
1022 buildTrace(*interpolationManager, game, symbolicMostProbablePathsResult.spanningTree, symbolicPivotStateResult.pivotState);
1023 auto end = std::chrono::high_resolution_clock::now();
1024 STORM_LOG_DEBUG("Building the trace and variable substitution for interpolation from symbolic most-probable paths result took "
1025 << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1026
1027 return derivePredicatesFromInterpolationFromTrace(*interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second);
1028}
1029
1030template<storm::dd::DdType Type, typename ValueType>
1031boost::optional<RefinementPredicates> MenuGameRefiner<Type, ValueType>::derivePredicatesFromInterpolation(
1032 storm::gbar::abstraction::MenuGame<Type, ValueType> const& /*game*/, ExplicitPivotStateResult<ValueType> const& pivotStateResult,
1033 storm::dd::Odd const& odd) const {
1034 // Game is not necessary if representation is explicit via odd
1035 // Create a new expression manager that we can use for the interpolation.
1036 AbstractionInformation<Type> const& abstractionInformation = abstractor.get().getAbstractionInformation();
1037 std::shared_ptr<storm::expressions::ExpressionManager> interpolationManager = abstractionInformation.getExpressionManager().clone();
1038
1039 // Build the trace of the most probable path in terms of which predicates hold in each step.
1040 auto start = std::chrono::high_resolution_clock::now();
1041 std::pair<std::vector<uint64_t>, std::vector<uint64_t>> labeledReversedPath = buildReversedLabeledPath(pivotStateResult);
1042
1043 // If the initial state is the pivot state, we can stop here.
1044 if (labeledReversedPath.first.size() == 1) {
1045 return boost::none;
1046 }
1047
1048 std::pair<std::vector<std::vector<storm::expressions::Expression>>, std::map<storm::expressions::Variable, storm::expressions::Expression>>
1049 traceAndVariableSubstitution = buildTraceFromReversedLabeledPath(*interpolationManager, labeledReversedPath.first, labeledReversedPath.second, odd);
1050 auto end = std::chrono::high_resolution_clock::now();
1051 STORM_LOG_DEBUG("Building the trace and variable substitution for interpolation from explicit most-probable paths result took "
1052 << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1053
1054 return derivePredicatesFromInterpolationFromTrace(*interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second);
1055}
1056
1057template<storm::dd::DdType Type, typename ValueType>
1059 SymbolicQualitativeGameResultMinMax<Type> const& qualitativeResult) const {
1060 STORM_LOG_TRACE("Trying refinement after qualitative check.");
1061 // Get all relevant strategies.
1062 storm::dd::Bdd<Type> minPlayer1Strategy = qualitativeResult.prob0Min.getPlayer1Strategy();
1063 storm::dd::Bdd<Type> minPlayer2Strategy = qualitativeResult.prob0Min.getPlayer2Strategy();
1064 storm::dd::Bdd<Type> maxPlayer1Strategy = qualitativeResult.prob1Max.getPlayer1Strategy();
1065 storm::dd::Bdd<Type> maxPlayer2Strategy = qualitativeResult.prob1Max.getPlayer2Strategy();
1066
1067 // Redirect all player 1 choices of the min strategy to that of the max strategy if this leads to a player 2
1068 // state that is also a prob 0 state.
1069 auto oldMinPlayer1Strategy = minPlayer1Strategy;
1070 minPlayer1Strategy = (maxPlayer1Strategy && qualitativeResult.prob0Min.getPlayer2States())
1071 .existsAbstract(game.getPlayer1Variables())
1072 .ite(maxPlayer1Strategy, minPlayer1Strategy);
1073
1074 // Compute all reached pivot states.
1075 PivotStateCandidatesResult<Type> pivotStateCandidatesResult =
1076 computePivotStates(game, transitionMatrixBdd, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1077
1078 // We can only refine in case we have a reachable player 1 state with a player 2 successor (under either
1079 // player 1's min or max strategy) such that from this player 2 state, both prob0 min and prob1 max define
1080 // strategies and they differ. Hence, it is possible that we arrive at a point where no suitable pivot state
1081 // is found. In this case, we abort the qualitative refinement here.
1082 if (pivotStateCandidatesResult.pivotStates.isZero()) {
1083 STORM_LOG_TRACE("Did not find pivot state in qualitative fragment.");
1084 return false;
1085 }
1086 STORM_LOG_ASSERT(!pivotStateCandidatesResult.pivotStates.isZero(), "Unable to proceed without pivot state candidates.");
1087
1088 // Now that we have the pivot state candidates, we need to pick one.
1089 SymbolicPivotStateResult<Type, ValueType> symbolicPivotStateResult =
1090 pickPivotState<Type, ValueType>(pivotSelectionHeuristic, game, pivotStateCandidatesResult, qualitativeResult, boost::none);
1091
1092 boost::optional<RefinementPredicates> predicates;
1093 if (useInterpolation) {
1094 predicates =
1095 derivePredicatesFromInterpolation(game, symbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1096 }
1097 if (predicates) {
1098 STORM_LOG_TRACE("Obtained predicates by interpolation.");
1099 } else {
1100 predicates = derivePredicatesFromPivotState(game, symbolicPivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy,
1101 maxPlayer2Strategy);
1102 }
1103 STORM_LOG_THROW(static_cast<bool>(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue.");
1104
1105 // Derive predicate based on the selected pivot state.
1106 std::vector<storm::expressions::Expression> preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource());
1107 performRefinement(createGlobalRefinement(preparedPredicates));
1108 return true;
1109}
1110
1111template<typename ValueType>
1114 // Intentionally left empty.
1115 }
1116
1117 ValueType distance;
1118 uint64_t state;
1119 bool lower;
1120};
1121
1122template<typename ValueType>
1125 if (a.distance < b.distance) {
1126 return true;
1127 } else if (a.distance > b.distance) {
1128 return false;
1129 } else {
1130 if (a.state < b.state) {
1131 return true;
1132 } else if (a.state > b.state) {
1133 return false;
1134 } else {
1135 if (a.lower < b.lower) {
1136 return true;
1137 } else {
1138 return false;
1139 }
1140 }
1141 }
1142 }
1143};
1144
1145template<typename ValueType>
1147 bool probabilityDistances, std::vector<ValueType>& distances, std::vector<std::pair<uint64_t, uint64_t>>& predecessors,
1148 bool generatePredecessors, bool lower, uint64_t currentState, ValueType const& currentDistance, [[maybe_unused]] bool isPivotState,
1149 storm::storage::ExplicitGameStrategyPair const& strategyPair,
1150 [[maybe_unused]] storm::storage::ExplicitGameStrategyPair const& otherStrategyPair, std::vector<uint64_t> const& player1Labeling,
1151 [[maybe_unused]] std::vector<uint64_t> const& player2Grouping, storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
1152 [[maybe_unused]] storm::storage::BitVector const& targetStates, storm::storage::BitVector const& relevantStates) {
1153 if (strategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) {
1154 uint64_t player2Successor = strategyPair.getPlayer1Strategy().getChoice(currentState);
1155 uint64_t player2Choice = strategyPair.getPlayer2Strategy().getChoice(player2Successor);
1156 STORM_LOG_ASSERT(isPivotState || !otherStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) ||
1157 strategyPair.getPlayer2Strategy().getChoice(player2Successor) == player2Choice,
1158 "Did not expect deviation in player 2 strategy.");
1159 STORM_LOG_ASSERT(player2Grouping[player2Successor] <= player2Choice && player2Choice < player2Grouping[player2Successor + 1],
1160 "Illegal choice for player 2.");
1161
1162 for (auto const& entry : transitionMatrix.getRow(player2Choice)) {
1163 uint64_t player1Successor = entry.getColumn();
1164 if (!relevantStates.get(player1Successor)) {
1165 continue;
1166 }
1167
1168 ValueType alternateDistance;
1169 if (probabilityDistances) {
1170 alternateDistance = currentDistance * entry.getValue();
1171 } else {
1172 alternateDistance = currentDistance + storm::utility::one<ValueType>();
1173 }
1174 if (probabilityDistances ? alternateDistance > distances[player1Successor] : alternateDistance < distances[player1Successor]) {
1175 distances[player1Successor] = alternateDistance;
1176 if (generatePredecessors) {
1177 predecessors[player1Successor] = std::make_pair(currentState, player1Labeling[player2Successor]);
1178 }
1179 dijkstraQueue.emplace(alternateDistance, player1Successor, lower);
1180 }
1181 }
1182 } else {
1183 STORM_LOG_ASSERT(targetStates.get(currentState), "Expecting min strategy for non-target states.");
1184 }
1185}
1186
1187template<typename ValueType>
1188boost::optional<ExplicitPivotStateResult<ValueType>> pickPivotState(
1189 bool generatePredecessors, AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic,
1190 storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<uint64_t> const& player1Labeling,
1191 storm::storage::BitVector const& initialStates, storm::storage::BitVector const& relevantStates, storm::storage::BitVector const& targetStates,
1192 storage::ExplicitGameStrategyPair const& minStrategyPair, storage::ExplicitGameStrategyPair const& maxStrategyPair,
1193 std::vector<ValueType> const* lowerValues = nullptr, std::vector<ValueType> const* upperValues = nullptr) {
1194 // The method used to have an unused player1Grouping.
1195 STORM_LOG_ASSERT(!lowerValues || upperValues, "Expected none or both value results.");
1196 STORM_LOG_ASSERT(!upperValues || lowerValues, "Expected none or both value results.");
1197
1198 // Perform Dijkstra search that stays within the relevant states and searches for a (pivot) state in which
1199 // the strategies the lower or upper player 1 action leads to a player 2 state in which the choices differ.
1200 // To guarantee that the pivot state is reachable by either of the strategies, we do a parallel Dijkstra
1201 // search in both the lower and upper strategy.
1202
1203 bool probabilityDistances = pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MostProbablePath;
1204 uint64_t numberOfStates = initialStates.size();
1205 ValueType inftyDistance = probabilityDistances ? storm::utility::zero<ValueType>() : storm::utility::infinity<ValueType>();
1206 ValueType zeroDistance = probabilityDistances ? storm::utility::one<ValueType>() : storm::utility::zero<ValueType>();
1207
1208 // Create storages for the lower and upper Dijkstra search.
1209 std::vector<ValueType> lowerDistances(numberOfStates, inftyDistance);
1210 std::vector<std::pair<uint64_t, uint64_t>> lowerPredecessors;
1211 std::vector<ValueType> upperDistances(numberOfStates, inftyDistance);
1212 std::vector<std::pair<uint64_t, uint64_t>> upperPredecessors;
1213
1214 if (generatePredecessors) {
1215 lowerPredecessors.resize(numberOfStates,
1217 upperPredecessors.resize(numberOfStates,
1219 }
1220
1221 // Use set as priority queue with unique membership.
1222 std::set<ExplicitDijkstraQueueElement<ValueType>, ExplicitDijkstraQueueElementLess<ValueType>> dijkstraQueue;
1223
1224 for (auto initialState : initialStates) {
1225 if (!relevantStates.get(initialState)) {
1226 continue;
1227 }
1228
1229 lowerDistances[initialState] = zeroDistance;
1230 upperDistances[initialState] = zeroDistance;
1231 dijkstraQueue.emplace(zeroDistance, initialState, true);
1232 dijkstraQueue.emplace(zeroDistance, initialState, false);
1233 }
1234
1235 // For some heuristics, we need to potentially find more than just one pivot.
1238 lowerValues && upperValues;
1239 bool foundPivotState = false;
1240
1241 ExplicitDijkstraQueueElement<ValueType> pivotState(inftyDistance, 0, true);
1242 ValueType pivotStateDeviation = storm::utility::zero<ValueType>();
1243 auto const& player2Grouping = transitionMatrix.getRowGroupIndices();
1244
1245 while (!dijkstraQueue.empty()) {
1246 // Take out currently best state.
1247 auto currentDijkstraElement = *dijkstraQueue.begin();
1248 ValueType currentDistance = currentDijkstraElement.distance;
1249 uint64_t currentState = currentDijkstraElement.state;
1250 bool currentLower = currentDijkstraElement.lower;
1251 dijkstraQueue.erase(dijkstraQueue.begin());
1252
1253 if (foundPivotState && (probabilityDistances ? currentDistance < pivotState.distance : currentDistance > pivotState.distance)) {
1255 // For the nearest maximal deviation and most probable path heuristics, future pivot states are
1256 // not important any more, because their distance will be strictly larger, so we can return the
1257 // current pivot state.
1258
1259 return ExplicitPivotStateResult<ValueType>(pivotState.state, pivotState.distance,
1260 pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors));
1261 } else if (pivotStateDeviation >= currentDistance) {
1262 // If the heuristic is maximal weighted deviation and the weighted deviation for any future pivot
1263 // state is necessarily at most as high as the current one, we can abort the search.
1264 return ExplicitPivotStateResult<ValueType>(pivotState.state, pivotState.distance,
1265 pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors));
1266 }
1267 }
1268
1269 // Determine whether the current state is a pivot state.
1270 bool isPivotState = false;
1271 if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) {
1272 uint64_t player2Successor = minStrategyPair.getPlayer1Strategy().getChoice(currentState);
1273 if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) &&
1274 maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) &&
1275 minStrategyPair.getPlayer2Strategy().getChoice(player2Successor) != maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor)) {
1276 isPivotState = true;
1277 }
1278 }
1279 if (!isPivotState && maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) {
1280 uint64_t player2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState);
1281 if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) &&
1282 maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) &&
1283 minStrategyPair.getPlayer2Strategy().getChoice(player2Successor) != maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor)) {
1284 isPivotState = true;
1285 }
1286 }
1287
1288 // If it is indeed a pivot state, we can potentially abort the search here.
1289 if (isPivotState) {
1290 if (considerDeviation && foundPivotState) {
1291 ValueType deviationOfCurrentState = (*upperValues)[currentState] - (*lowerValues)[currentState];
1292
1293 if (deviationOfCurrentState > pivotStateDeviation) {
1294 pivotState = currentDijkstraElement;
1295 pivotStateDeviation = deviationOfCurrentState;
1297 // Scale the deviation with the distance (probability) for this heuristic.
1298 pivotStateDeviation *= currentDistance;
1299 }
1300 }
1301 } else if (!foundPivotState) {
1302 pivotState = currentDijkstraElement;
1303 foundPivotState = true;
1304 }
1305
1306 // If there is no need to look at other deviations, stop here.
1307 if (!considerDeviation) {
1308 return ExplicitPivotStateResult<ValueType>(pivotState.state, pivotState.distance,
1309 pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors));
1310 }
1311 }
1312
1313 // We only need to search further if the state has some value deviation.
1314 if (!lowerValues || !upperValues || (*lowerValues)[currentState] < (*upperValues)[currentState]) {
1315 if (currentLower) {
1316 performDijkstraStep(dijkstraQueue, probabilityDistances, lowerDistances, lowerPredecessors, generatePredecessors, true, currentState,
1317 currentDistance, isPivotState, minStrategyPair, maxStrategyPair, player1Labeling, player2Grouping, transitionMatrix,
1318 targetStates, relevantStates);
1319 } else {
1320 performDijkstraStep(dijkstraQueue, probabilityDistances, upperDistances, upperPredecessors, generatePredecessors, false, currentState,
1321 currentDistance, isPivotState, maxStrategyPair, minStrategyPair, player1Labeling, player2Grouping, transitionMatrix,
1322 targetStates, relevantStates);
1323 }
1324 }
1325 }
1326
1327 if (foundPivotState) {
1328 return ExplicitPivotStateResult<ValueType>(pivotState.state, pivotState.distance,
1329 pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors));
1330 }
1331
1332 // If we arrived at this point, we have explored all relevant states, but none of them was a pivot state,
1333 // which can happen when trying to refine using the qualitative result only.
1334 STORM_LOG_TRACE("Did not find pivot state in explicit Dijkstra search.");
1335 return boost::none;
1336}
1337
1338template<storm::dd::DdType Type, typename ValueType>
1339boost::optional<RefinementPredicates> MenuGameRefiner<Type, ValueType>::derivePredicatesFromInterpolationReversedPath(
1340 storm::dd::Odd const& odd, storm::expressions::ExpressionManager& interpolationManager, std::vector<uint64_t> const& reversedPath,
1341 std::vector<uint64_t> const& stateToOffset, std::vector<uint64_t> const& reversedLabels) const {
1342 // Build the trace of the most probable path in terms of which predicates hold in each step.
1343 auto start = std::chrono::high_resolution_clock::now();
1344 std::pair<std::vector<std::vector<storm::expressions::Expression>>, std::map<storm::expressions::Variable, storm::expressions::Expression>>
1345 traceAndVariableSubstitution = buildTraceFromReversedLabeledPath(interpolationManager, reversedPath, reversedLabels, odd, &stateToOffset);
1346 auto end = std::chrono::high_resolution_clock::now();
1347 STORM_LOG_DEBUG("Building the trace and variable substitution for interpolation from explicit most-probable paths result took "
1348 << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1349
1350 return derivePredicatesFromInterpolationFromTrace(interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second);
1351}
1352
1353template<storm::dd::DdType Type, typename ValueType>
1355 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
1356 [[maybe_unused]] std::vector<uint64_t> const& player1Grouping, std::vector<uint64_t> const& player1Labeling,
1357 std::vector<uint64_t> const& player2Labeling, storm::storage::BitVector const& initialStates,
1358 storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates,
1359 ExplicitQualitativeGameResultMinMax const& qualitativeResult,
1360 storage::ExplicitGameStrategyPair const& minStrategyPair,
1361 storage::ExplicitGameStrategyPair const& maxStrategyPair) const {
1362 STORM_LOG_ASSERT(constraintStates.full(), "Constraint states are ignored. Likely buggy.");
1363 (void)constraintStates; // Disable warning, in debug mode we monitor wrong usage of this method.
1364 // Compute the set of states whose result we have for the min and max case.
1365 storm::storage::BitVector relevantStates = (qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()) &
1366 (qualitativeResult.getProb0Max().getStates() | qualitativeResult.getProb1Max().getStates());
1367
1368 boost::optional<ExplicitPivotStateResult<ValueType>> optionalPivotStateResult =
1369 pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Labeling, initialStates, relevantStates, targetStates,
1370 minStrategyPair, maxStrategyPair);
1371
1372 // If there was no pivot state, continue the search.
1373 if (!optionalPivotStateResult) {
1374 STORM_LOG_TRACE("Did not find pivot state in qualitative fragment.");
1375 return false;
1376 }
1377
1378 // Otherwise, we can refine.
1379 auto const& pivotStateResult = optionalPivotStateResult.get();
1380 STORM_LOG_TRACE("Found pivot state " << pivotStateResult.pivotState << " with distance " << pivotStateResult.distance << ".");
1381
1382 // Translate the explicit states/choices to the symbolic ones, so we can reuse the predicate derivation techniques.
1383 auto const& abstractionInformation = abstractor.get().getAbstractionInformation();
1384 uint64_t pivotState = pivotStateResult.pivotState;
1385 storm::dd::Bdd<Type> symbolicPivotState = storm::dd::Bdd<Type>::getEncoding(game.getManager(), pivotState, odd, game.getRowVariables());
1386 storm::dd::Bdd<Type> minPlayer1Strategy = game.getManager().getBddZero();
1387 storm::dd::Bdd<Type> maxPlayer1Strategy = game.getManager().getBddZero();
1388 storm::dd::Bdd<Type> minPlayer2Strategy = game.getManager().getBddZero();
1389 storm::dd::Bdd<Type> maxPlayer2Strategy = game.getManager().getBddZero();
1390 if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) {
1391 uint64_t player2State = minStrategyPair.getPlayer1Strategy().getChoice(pivotState);
1392 STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1.");
1393 minPlayer1Strategy |=
1394 symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount());
1395
1396 if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) {
1397 uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State);
1398 minPlayer2Strategy |=
1399 minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size());
1400 }
1401 if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) {
1402 uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State);
1403 maxPlayer2Strategy |=
1404 minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size());
1405 }
1406 }
1407 if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) {
1408 uint64_t player2State = maxStrategyPair.getPlayer1Strategy().getChoice(pivotState);
1409 STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1.");
1410 maxPlayer1Strategy |=
1411 symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount());
1412
1413 if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) {
1414 uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State);
1415 minPlayer2Strategy |=
1416 maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size());
1417 }
1418 if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) {
1419 uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State);
1420 maxPlayer2Strategy |=
1421 maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size());
1422 }
1423 }
1424 auto end = std::chrono::high_resolution_clock::now();
1425
1426 boost::optional<RefinementPredicates> predicates;
1427 if (useInterpolation) {
1428 predicates = derivePredicatesFromInterpolation(game, pivotStateResult, odd);
1429 }
1430 if (!predicates) {
1431 predicates = derivePredicatesFromPivotState(game, symbolicPivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1432 }
1433 end = std::chrono::high_resolution_clock::now();
1434 STORM_LOG_THROW(static_cast<bool>(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue.");
1435
1436 std::vector<storm::expressions::Expression> preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource());
1437 performRefinement(createGlobalRefinement(preparedPredicates));
1438 return true;
1439}
1440
1441template<storm::dd::DdType Type, typename ValueType>
1443 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
1444 [[maybe_unused]] std::vector<uint64_t> const& player1Grouping, std::vector<uint64_t> const& player1Labeling,
1445 std::vector<uint64_t> const& player2Labeling, storm::storage::BitVector const& initialStates,
1446 storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates,
1447 ExplicitQuantitativeResultMinMax<ValueType> const& quantitativeResult,
1448 storage::ExplicitGameStrategyPair const& minStrategyPair,
1449 storage::ExplicitGameStrategyPair const& maxStrategyPair) const {
1450 STORM_LOG_ASSERT(constraintStates.full(), "Constraint states are ignored. Likely buggy.");
1451 (void)constraintStates; // Disable warning, in debug mode we monitor wrong usage of this method.
1452
1453 // Compute the set of states whose result we have for the min and max case.
1454 storm::storage::BitVector relevantStates(odd.getTotalOffset(), true);
1455
1456 boost::optional<ExplicitPivotStateResult<ValueType>> optionalPivotStateResult =
1457 pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Labeling, initialStates, relevantStates, targetStates,
1458 minStrategyPair, maxStrategyPair, &quantitativeResult.getMin().getValues(), &quantitativeResult.getMax().getValues());
1459
1460 STORM_LOG_THROW(optionalPivotStateResult, storm::exceptions::InvalidStateException, "Did not find pivot state to proceed.");
1461
1462 // Otherwise, we can refine.
1463 auto const& pivotStateResult = optionalPivotStateResult.get();
1464 STORM_LOG_TRACE("Found pivot state " << pivotStateResult.pivotState << " with distance " << pivotStateResult.distance << ".");
1465
1466 // Translate the explicit states/choices to the symbolic ones, so we can reuse the predicate derivation techniques.
1467 auto const& abstractionInformation = abstractor.get().getAbstractionInformation();
1468 uint64_t pivotState = pivotStateResult.pivotState;
1469 storm::dd::Bdd<Type> symbolicPivotState = storm::dd::Bdd<Type>::getEncoding(game.getManager(), pivotState, odd, game.getRowVariables());
1470 storm::dd::Bdd<Type> minPlayer1Strategy = game.getManager().getBddZero();
1471 storm::dd::Bdd<Type> maxPlayer1Strategy = game.getManager().getBddZero();
1472 storm::dd::Bdd<Type> minPlayer2Strategy = game.getManager().getBddZero();
1473 storm::dd::Bdd<Type> maxPlayer2Strategy = game.getManager().getBddZero();
1474 if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) {
1475 uint64_t player2State = minStrategyPair.getPlayer1Strategy().getChoice(pivotState);
1476 STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1.");
1477 minPlayer1Strategy |=
1478 symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount());
1479
1480 if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) {
1481 uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State);
1482 minPlayer2Strategy |=
1483 minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size());
1484 }
1485 if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) {
1486 uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State);
1487 maxPlayer2Strategy |=
1488 minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size());
1489 }
1490 }
1491 if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) {
1492 uint64_t player2State = maxStrategyPair.getPlayer1Strategy().getChoice(pivotState);
1493 STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1.");
1494 maxPlayer1Strategy |=
1495 symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount());
1496
1497 if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) {
1498 uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State);
1499 minPlayer2Strategy |=
1500 maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size());
1501 }
1502 if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) {
1503 uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State);
1504 maxPlayer2Strategy |=
1505 maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size());
1506 }
1507 }
1508
1509 boost::optional<RefinementPredicates> predicates;
1510 if (useInterpolation) {
1511 predicates = derivePredicatesFromInterpolation(game, pivotStateResult, odd);
1512 }
1513 if (!predicates) {
1514 predicates = derivePredicatesFromPivotState(game, symbolicPivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1515 }
1516 STORM_LOG_THROW(static_cast<bool>(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue.");
1517
1518 std::vector<storm::expressions::Expression> preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource());
1519 performRefinement(createGlobalRefinement(preparedPredicates));
1520 return true;
1521}
1522
1523template<storm::dd::DdType Type, typename ValueType>
1525 SymbolicQuantitativeGameResultMinMax<Type, ValueType> const& quantitativeResult) const {
1526 STORM_LOG_TRACE("Refining after quantitative check.");
1527 // Get all relevant strategies.
1528 storm::dd::Bdd<Type> minPlayer1Strategy = quantitativeResult.min.getPlayer1Strategy();
1529 storm::dd::Bdd<Type> minPlayer2Strategy = quantitativeResult.min.getPlayer2Strategy();
1530 storm::dd::Bdd<Type> maxPlayer1Strategy = quantitativeResult.max.getPlayer1Strategy();
1531 storm::dd::Bdd<Type> maxPlayer2Strategy = quantitativeResult.max.getPlayer2Strategy();
1532
1533 // Compute all reached pivot states.
1534 PivotStateCandidatesResult<Type> pivotStateCandidatesResult =
1535 computePivotStates(game, transitionMatrixBdd, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1536
1537 STORM_LOG_ASSERT(!pivotStateCandidatesResult.pivotStates.isZero(), "Unable to refine without pivot state candidates.");
1538
1539 // Now that we have the pivot state candidates, we need to pick one.
1540 SymbolicPivotStateResult<Type, ValueType> symbolicPivotStateResult =
1541 pickPivotState<Type, ValueType>(pivotSelectionHeuristic, game, pivotStateCandidatesResult, boost::none, quantitativeResult);
1542
1543 boost::optional<RefinementPredicates> predicates;
1544 if (useInterpolation) {
1545 predicates =
1546 derivePredicatesFromInterpolation(game, symbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1547 }
1548 if (predicates) {
1549 STORM_LOG_TRACE("Obtained predicates by interpolation.");
1550 } else {
1551 predicates = derivePredicatesFromPivotState(game, symbolicPivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy,
1552 maxPlayer2Strategy);
1553 }
1554 STORM_LOG_THROW(static_cast<bool>(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue.");
1555
1556 std::vector<storm::expressions::Expression> preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource());
1557 performRefinement(createGlobalRefinement(preparedPredicates));
1558 return true;
1559}
1560
1562 std::size_t operator()(std::set<storm::expressions::Variable> const& set) const {
1563 return set.size();
1564 }
1565};
1566
1567template<storm::dd::DdType Type, typename ValueType>
1568std::vector<storm::expressions::Expression> MenuGameRefiner<Type, ValueType>::preprocessPredicates(
1569 std::vector<storm::expressions::Expression> const& predicates, RefinementPredicates::Source const& source) const {
1570 bool split = source == RefinementPredicates::Source::WeakestPrecondition && splitPredicates;
1571 split |= source == RefinementPredicates::Source::Interpolation && splitPredicates;
1572 split |= splitAll;
1573
1574 if (split) {
1575 auto start = std::chrono::high_resolution_clock::now();
1576 AbstractionInformation<Type> const& abstractionInformation = abstractor.get().getAbstractionInformation();
1577 std::vector<storm::expressions::Expression> cleanedAtoms;
1578
1579 std::unordered_map<std::set<storm::expressions::Variable>, std::vector<storm::expressions::Expression>, VariableSetHash> predicateClasses;
1580
1581 for (auto const& predicate : predicates) {
1582 // Split the predicates.
1583 std::vector<storm::expressions::Expression> atoms = splitter.split(predicate);
1584
1585 // Put the atoms into the right class.
1586 for (auto const& atom : atoms) {
1587 std::set<storm::expressions::Variable> vars = atom.getVariables();
1588 predicateClasses[vars].push_back(atom);
1589 }
1590 }
1591
1592 // Now clean the classes in the sense that redundant predicates are cleaned.
1593 uint64_t checkCounter = 0;
1594 for (auto& predicateClass : predicateClasses) {
1595 std::vector<storm::expressions::Expression> cleanedAtomsOfClass;
1596
1597 for (auto const& predicate : predicateClass.second) {
1598 bool addPredicate = true;
1599 for (auto const& atom : cleanedAtomsOfClass) {
1600 if (predicate.areSame(atom)) {
1601 addPredicate = false;
1602 break;
1603 }
1604
1605 ++checkCounter;
1606 if (equivalenceChecker.areEquivalentModuloNegation(predicate, atom)) {
1607 addPredicate = false;
1608 break;
1609 }
1610 }
1611 if (addPredicate) {
1612 cleanedAtomsOfClass.push_back(predicate);
1613 }
1614 }
1615
1616 predicateClass.second = std::move(cleanedAtomsOfClass);
1617 }
1618
1619 std::unordered_map<std::set<storm::expressions::Variable>, std::vector<storm::expressions::Expression>, VariableSetHash> oldPredicateClasses;
1620 for (auto const& oldPredicate : abstractionInformation.getPredicates()) {
1621 std::set<storm::expressions::Variable> vars = oldPredicate.getVariables();
1622
1623 oldPredicateClasses[vars].push_back(oldPredicate);
1624 }
1625
1626 for (auto const& predicateClass : predicateClasses) {
1627 auto oldPredicateClassIt = oldPredicateClasses.find(predicateClass.first);
1628 if (oldPredicateClassIt != oldPredicateClasses.end()) {
1629 for (auto const& newAtom : predicateClass.second) {
1630 bool addAtom = true;
1631 for (auto const& oldPredicate : oldPredicateClassIt->second) {
1632 if (newAtom.areSame(oldPredicate)) {
1633 addAtom = false;
1634 break;
1635 }
1636 ++checkCounter;
1637 if (equivalenceChecker.areEquivalentModuloNegation(newAtom, oldPredicate)) {
1638 addAtom = false;
1639 break;
1640 }
1641 }
1642 if (addAtom) {
1643 cleanedAtoms.push_back(newAtom);
1644 }
1645 }
1646 } else {
1647 cleanedAtoms.insert(cleanedAtoms.end(), predicateClass.second.begin(), predicateClass.second.end());
1648 }
1649 }
1650 auto end = std::chrono::high_resolution_clock::now();
1651 STORM_LOG_TRACE("Preprocessing predicates took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms (" << checkCounter
1652 << " checks).");
1653
1654 return cleanedAtoms;
1655 } else {
1656 // If no splitting of the predicates is required, just forward the refinement request to the abstractor.
1657 }
1658
1659 return predicates;
1660}
1661
1662template<storm::dd::DdType Type, typename ValueType>
1663std::vector<RefinementCommand> MenuGameRefiner<Type, ValueType>::createGlobalRefinement(std::vector<storm::expressions::Expression> const& predicates) const {
1664 std::vector<RefinementCommand> commands;
1665 commands.emplace_back(predicates);
1666 return commands;
1667}
1668
1669template<storm::dd::DdType Type, typename ValueType>
1670void MenuGameRefiner<Type, ValueType>::performRefinement(std::vector<RefinementCommand> const& refinementCommands, bool allowInjection) const {
1671 if (!refinementPredicatesToInject.empty() && allowInjection) {
1672 STORM_LOG_INFO("Refining with (injected) predicates.");
1673
1674 for (auto const& predicate : refinementPredicatesToInject.back()) {
1675 STORM_LOG_INFO(predicate);
1676 }
1677
1678 abstractor.get().refine(RefinementCommand(refinementPredicatesToInject.back()));
1679 refinementPredicatesToInject.pop_back();
1680 } else {
1681 for (auto const& command : refinementCommands) {
1682 STORM_LOG_INFO("Refining with " << command.getPredicates().size() << " predicates.");
1683 for (auto const& predicate : command.getPredicates()) {
1684 STORM_LOG_INFO(predicate);
1685 }
1686 if (!command.getPredicates().empty()) {
1687 abstractor.get().refine(command);
1688 }
1689 }
1690 }
1691
1692 STORM_LOG_TRACE("Current set of predicates:");
1693 for (auto const& predicate : abstractor.get().getAbstractionInformation().getPredicates()) {
1694 STORM_LOG_TRACE(predicate);
1695 }
1696}
1697
1698template<storm::dd::DdType Type, typename ValueType>
1700 return addedAllGuardsFlag;
1701}
1702
1706
1707#ifdef STORM_HAVE_CARL
1708// Currently, this instantiation does not work.
1709// template class MenuGameRefiner<storm::dd::DdType::Sylvan, storm::RationalFunction>;
1710#endif
1711
1712} // namespace abstraction
1713} // namespace storm::gbar
ValueType getMax() const
Retrieves the highest function value of any encoding.
Definition Add.cpp:475
Bdd< LibraryType > greater(Add< LibraryType, ValueType > const &other) const
Retrieves the function that maps all evaluations to one whose function value in the first ADD are gre...
Definition Add.cpp:116
Add< LibraryType, ValueType > maximum(Add< LibraryType, ValueType > const &other) const
Retrieves the function that maps all evaluations to the maximum of the function values of the two ADD...
Definition Add.cpp:173
Add< LibraryType, ValueType > maxAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Max-abstracts from the given meta variables.
Definition Add.cpp:198
AddIterator< LibraryType, ValueType > begin(bool enumerateDontCareMetaVariables=true) const
Retrieves an iterator that points to the first meta variable assignment with a non-zero function valu...
Definition Add.cpp:1149
Bdd< LibraryType > toBdd() const
Converts the ADD to a BDD by mapping all values unequal to zero to 1.
Definition Add.cpp:1187
Bdd< LibraryType > maxAbstractRepresentative(std::set< storm::expressions::Variable > const &metaVariables) const
Similar to maxAbstract, but does not abstract from the variables but rather picks a valuation of each...
Definition Add.cpp:205
Bdd< LibraryType > existsAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Existentially abstracts from the given meta variables.
Definition Bdd.cpp:178
bool isZero() const
Retrieves whether this DD represents the constant zero function.
Definition Bdd.cpp:547
virtual uint_fast64_t getNonZeroCount() const override
Retrieves the number of encodings that are mapped to a non-zero value.
Definition Bdd.cpp:513
static Bdd< LibraryType > getEncoding(DdManager< LibraryType > const &ddManager, uint64_t targetOffset, storm::dd::Odd const &odd, std::set< storm::expressions::Variable > const &metaVariables)
Constructs the BDD representation of the encoding with the given offset.
Definition Bdd.cpp:94
Bdd< LibraryType > swapVariables(std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > const &metaVariablePairs) const
Swaps the given pairs of meta variables in the BDD.
Definition Bdd.cpp:302
Bdd< LibraryType > existsAbstractRepresentative(std::set< storm::expressions::Variable > const &metaVariables) const
Similar to existsAbstract, but does not abstract from the variables but rather picks a valuation of e...
Definition Bdd.cpp:184
Bdd< LibraryType > ite(Bdd< LibraryType > const &thenBdd, Bdd< LibraryType > const &elseBdd) const
Performs an if-then-else with the given operands, i.e.
Definition Bdd.cpp:113
Bdd< LibraryType > exclusiveOr(Bdd< LibraryType > const &other) const
Performs a logical exclusive-or of the current and the given BDD.
Definition Bdd.cpp:157
Bdd< LibraryType > relationalProduct(Bdd< LibraryType > const &relation, std::set< storm::expressions::Variable > const &rowMetaVariables, std::set< storm::expressions::Variable > const &columnMetaVariables) const
Computes the relational product of the current BDD and the given BDD representing a relation.
Definition Bdd.cpp:220
uint_fast64_t getTotalOffset() const
Retrieves the total offset, i.e., the sum of the then- and else-offset.
Definition Odd.cpp:47
storm::storage::BitVector getEncoding(uint64_t offset, uint64_t variableCount=0) const
Retrieves the encoding for the given offset.
Definition Odd.cpp:190
void addConstraints(std::vector< storm::expressions::Expression > const &constraints)
bool isFalse() const
Checks if the expression is equal to the boolean literal false.
std::set< storm::expressions::Variable > getVariables() const
Retrieves the set of all variables that appear in the expression.
Expression changeManager(ExpressionManager const &newExpressionManager) const
Converts the expression to an expression over the variables of the provided expression manager.
Expression substitute(std::map< Variable, Expression > const &variableToExpressionMap) const
Substitutes all occurrences of the variables according to the given map.
bool isTrue() const
Checks if the expression is equal to the boolean literal true.
bool isInitialized() const
Checks whether the object encapsulates a base-expression.
This class is responsible for managing a set of typed variables and all expressions using these varia...
std::shared_ptr< ExpressionManager > clone() const
Creates a new expression manager with the same set of variables.
Variable declareVariableCopy(Variable const &variable)
Declares a variable that is a copy of the provided variable (i.e.
Variable getVariable(std::string const &name) const
Retrieves the expression that represents the variable with the given name.
Expression boolean(bool value) const
Creates an expression that characterizes the given boolean literal.
bool hasBooleanType() const
Checks whether the variable is of boolean type.
Definition Variable.cpp:59
virtual storm::storage::BitVector const & getStates() const =0
ExplicitQuantitativeResult< ValueType > const & getMin() const
ExplicitQuantitativeResult< ValueType > const & getMax() const
virtual storm::expressions::Expression getInitialExpression() const =0
virtual storm::expressions::Expression const & getGuard(uint64_t player1Choice) const =0
virtual std::pair< uint64_t, uint64_t > getPlayer1ChoiceRange() const =0
virtual void notifyGuardsArePredicates()=0
Notifies the abstractor that the guards are predicates, which may be used to improve the bottom state...
virtual AbstractionInformation< DdType > const & getAbstractionInformation() const =0
Retrieves information about the abstraction.
This class represents a discrete-time stochastic two-player game.
Definition MenuGame.h:16
std::set< storm::expressions::Variable > const & getProbabilisticBranchingVariables() const
Retrieves the variables used to encode additional information for the probabilistic branching in the ...
Definition MenuGame.cpp:78
storm::dd::Add< Type, ValueType > const & getExtendedTransitionMatrix() const
Retrieves the transition matrix extended by variables that encode additional information for the prob...
Definition MenuGame.cpp:73
bool addedAllGuards() const
Retrieves whether all guards were added.
MenuGameRefiner(MenuGameAbstractor< Type, ValueType > &abstractor, std::unique_ptr< storm::solver::SmtSolver > &&smtSolver, MenuGameRefinerOptions const &options=MenuGameRefinerOptions())
Creates a refiner for the provided abstractor.
void refine(std::vector< storm::expressions::Expression > const &predicates, bool allowInjection=true) const
Refines the abstractor with the given predicates.
void addPredicates(std::vector< storm::expressions::Expression > const &newPredicates)
std::vector< storm::expressions::Expression > const & getPredicates() const
storm::dd::DdManager< Type > & getManager() const
Retrieves the manager responsible for the DDs that represent this model.
Definition Model.cpp:92
std::set< storm::expressions::Variable > const & getColumnVariables() const
Retrieves the meta variables used to encode the columns of the transition matrix and the vector indic...
Definition Model.cpp:197
storm::dd::Bdd< Type > const & getInitialStates() const
Retrieves the initial states of the model.
Definition Model.cpp:107
std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > const & getRowColumnMetaVariablePairs() const
Retrieves the pairs of row and column meta variables.
Definition Model.cpp:223
std::set< storm::expressions::Variable > const & getRowVariables() const
Retrieves the meta variables used to encode the rows of the transition matrix and the vector indices.
Definition Model.cpp:192
virtual std::set< storm::expressions::Variable > const & getNondeterminismVariables() const override
Retrieves the meta variables used to encode the nondeterminism in the model.
std::set< storm::expressions::Variable > const & getPlayer1Variables() const
Retrieeves the set of meta variables used to encode the nondeterministic choices of player 1.
std::set< storm::expressions::Variable > const & getPlayer2Variables() const
Retrieeves the set of meta variables used to encode the nondeterministic choices of player 2.
This class represents the settings for the abstraction procedures.
A class that captures options that may be passed to the Mathsat solver.
CheckResult
possible check results
Definition SmtSolver.h:25
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
const_reverse_iterator rbegin() const
Returns a reverse iterator to the indices of the set bits in the bit vector.
bool full() const
Retrieves whether all bits are set in this bit vector.
size_t size() const
Retrieves the number of bits this bit vector can store.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
bool hasDefinedChoice(uint64_t state) const
uint64_t getChoice(uint64_t state) const
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.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
#define STORM_LOG_INFO(message)
Definition logging.h:29
#define STORM_LOG_DEBUG(message)
Definition logging.h:23
#define STORM_LOG_TRACE(message)
Definition logging.h:17
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
Expression ite(Expression const &condition, Expression const &thenExpression, Expression const &elseExpression)
Expression iff(Expression const &first, Expression const &second)
SymbolicPivotStateResult< Type, ValueType > pickPivotState(AbstractionSettings::PivotSelectionHeuristic const &heuristic, storm::gbar::abstraction::MenuGame< Type, ValueType > const &game, PivotStateCandidatesResult< Type > const &pivotStateCandidateResult, boost::optional< SymbolicQualitativeGameResultMinMax< Type > > const &qualitativeResult, boost::optional< SymbolicQuantitativeGameResultMinMax< Type, ValueType > > const &quantitativeResult)
PivotStateCandidatesResult< Type > computePivotStates(storm::gbar::abstraction::MenuGame< Type, ValueType > const &game, storm::dd::Bdd< Type > const &transitionMatrixBdd, storm::dd::Bdd< Type > const &minPlayer1Strategy, storm::dd::Bdd< Type > const &minPlayer2Strategy, storm::dd::Bdd< Type > const &maxPlayer1Strategy, storm::dd::Bdd< Type > const &maxPlayer2Strategy)
SymbolicMostProbablePathsResult< Type, ValueType > getMostProbablePathSpanningTree(storm::gbar::abstraction::MenuGame< Type, ValueType > const &game, storm::dd::Bdd< Type > const &transitionFilter)
void performDijkstraStep(std::set< ExplicitDijkstraQueueElement< ValueType >, ExplicitDijkstraQueueElementLess< ValueType > > &dijkstraQueue, bool probabilityDistances, std::vector< ValueType > &distances, std::vector< std::pair< uint64_t, uint64_t > > &predecessors, bool generatePredecessors, bool lower, uint64_t currentState, ValueType const &currentDistance, bool isPivotState, storm::storage::ExplicitGameStrategyPair const &strategyPair, storm::storage::ExplicitGameStrategyPair const &otherStrategyPair, std::vector< uint64_t > const &player1Labeling, std::vector< uint64_t > const &player2Grouping, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::BitVector const &targetStates, storm::storage::BitVector const &relevantStates)
std::pair< storm::RationalNumber, storm::RationalNumber > count(std::vector< storm::storage::BitVector > const &origSets, std::vector< storm::storage::BitVector > const &intersects, std::vector< storm::storage::BitVector > const &intersectsInfo, storm::RationalNumber val, bool plus, uint64_t remdepth)
SettingsType const & getModule()
Get module.
std::pair< storm::dd::Bdd< Type >, uint64_t > computeReachableStates(storm::dd::Bdd< Type > const &initialStates, storm::dd::Bdd< Type > const &transitions, std::set< storm::expressions::Variable > const &rowMetaVariables, std::set< storm::expressions::Variable > const &columnMetaVariables)
Definition dd.cpp:16
LabParser.cpp.
Definition cli.cpp:18
ExplicitDijkstraQueueElement(ValueType const &distance, uint64_t state, bool lower)
bool operator()(ExplicitDijkstraQueueElement< ValueType > const &a, ExplicitDijkstraQueueElement< ValueType > const &b) const
static const uint64_t NO_PREDECESSOR
The value filled in for states without predecessors in the search.
SymbolicPivotStateResult(storm::dd::Bdd< Type > const &pivotState, storm::OptimizationDirection fromDirection, boost::optional< SymbolicMostProbablePathsResult< Type, ValueType > > const &symbolicMostProbablePathsResult=boost::none)
std::size_t operator()(std::set< storm::expressions::Variable > const &set) const