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