21 : source(source), predicates(predicates) {
34 this->predicates.insert(this->predicates.end(), newPredicates.begin(), newPredicates.end());
37template<storm::dd::DdType Type,
typename ValueType>
44template<storm::dd::DdType Type>
51template<storm::dd::DdType Type,
typename ValueType>
59template<storm::dd::DdType Type,
typename ValueType>
62 : abstractor(abstractor),
63 useInterpolation(options.useInterpolation),
66 rankPredicates(options.rankRefinementPredicates),
67 addPredicatesEagerly(options.useEagerRefinement),
68 addedAllGuardsFlag(false),
69 refinementPredicatesToInject(options.injectedRefinementPredicates),
70 pivotSelectionHeuristic(options.pivotSelectionHeuristic),
72 equivalenceChecker(
std::move(smtSolver)) {
73 equivalenceChecker.addConstraints(abstractor.getAbstractionInformation().getConstraints());
75 std::vector<storm::expressions::Expression> guards;
77 std::pair<uint64_t, uint64_t> player1Choices = this->abstractor.get().getPlayer1ChoiceRange();
78 for (uint64_t index = player1Choices.first; index < player1Choices.second; ++index) {
79 storm::expressions::Expression guard = this->abstractor.get().getGuard(index);
80 if (!guard.isTrue() && !guard.isFalse()) {
81 guards.push_back(guard);
86 this->abstractor.get().notifyGuardsArePredicates();
87 addedAllGuardsFlag =
true;
89 if (options.addAllInitialExpressions) {
90 storm::expressions::Expression initialExpression = this->abstractor.get().getInitialExpression();
95template<storm::dd::DdType Type,
typename ValueType>
100template<storm::dd::DdType Type,
typename ValueType>
110 .template toAdd<ValueType>() *
114 std::set<storm::expressions::Variable> variablesToAbstract(game.
getRowVariables());
117 while (!border.
isZero()) {
125 maxProbabilities = updateStates.
ite(newMaxProbabilities, maxProbabilities);
134 border = updateStates;
140template<storm::dd::DdType Type,
typename ValueType>
151 if (qualitativeResult) {
152 minPlayer1Strategy = qualitativeResult.get().prob0Min.getPlayer1Strategy();
153 minPlayer2Strategy = qualitativeResult.get().prob0Min.getPlayer2Strategy();
154 maxPlayer1Strategy = qualitativeResult.get().prob1Max.getPlayer1Strategy();
155 maxPlayer2Strategy = qualitativeResult.get().prob1Max.getPlayer2Strategy();
156 }
else if (quantitativeResult) {
157 minPlayer1Strategy = quantitativeResult.get().min.getPlayer1Strategy();
158 minPlayer2Strategy = quantitativeResult.get().min.getPlayer2Strategy();
159 maxPlayer1Strategy = quantitativeResult.get().max.getPlayer1Strategy();
160 maxPlayer2Strategy = quantitativeResult.get().max.getPlayer2Strategy();
162 STORM_LOG_ASSERT(
false,
"Either qualitative or quantitative result is required.");
170 std::set<storm::expressions::Variable>
const& rowVariables = game.
getRowVariables();
171 std::set<storm::expressions::Variable>
const& columnVariables = game.
getColumnVariables();
180 bool foundPivotState = !frontierPivotStates.
isZero();
181 if (foundPivotState) {
183 << pivotStates.getNonZeroCount() <<
" candidates in total.");
185 storm::OptimizationDirection::Minimize);
189 while (!foundPivotState) {
190 frontierMin = frontierMin.
relationalProduct(transitionsMin, rowVariables, columnVariables);
191 frontierMax = frontierMax.
relationalProduct(transitionsMax, rowVariables, columnVariables);
198 if (!frontierMinPivotStates.
isZero() || !frontierMaxPivotStates.
isZero()) {
199 if (quantitativeResult) {
204 frontierMinPivotStatesAdd * quantitativeResult.get().max.values - frontierMinPivotStatesAdd * quantitativeResult.get().min.values;
206 frontierMaxPivotStatesAdd * quantitativeResult.get().max.values - frontierMaxPivotStatesAdd * quantitativeResult.get().min.values;
211 direction = storm::OptimizationDirection::Minimize;
212 diffValue = diffMin.
getMax();
214 direction = storm::OptimizationDirection::Maximize;
215 diffValue = diffMax.
getMax();
218 STORM_LOG_TRACE(
"Picked pivot state with difference " << diffValue <<
" from " << numberOfPivotStateCandidatesOnLevel
219 <<
" candidates on level " << level <<
", " << pivotStates.getNonZeroCount()
220 <<
" candidates in total.");
226 STORM_LOG_TRACE(
"Picked pivot state from " << numberOfPivotStateCandidatesOnLevel <<
" candidates on level " << level <<
", "
227 << pivotStates.getNonZeroCount() <<
" candidates in total.");
230 if (!frontierMinPivotStates.
isZero()) {
231 direction = storm::OptimizationDirection::Minimize;
233 direction = storm::OptimizationDirection::Maximize;
256 score = score * (quantitativeResult.get().max.values - quantitativeResult.get().min.values);
263 if ((selectedPivotStateAsAdd * maxSymbolicMostProbablePathsResult.
maxProbabilities).getMax() >
264 (selectedPivotStateAsAdd * minSymbolicMostProbablePathsResult.
maxProbabilities).getMax()) {
265 fromDirection = storm::OptimizationDirection::Maximize;
269 selectedPivotState, fromDirection,
270 fromDirection == storm::OptimizationDirection::Minimize ? minSymbolicMostProbablePathsResult : maxSymbolicMostProbablePathsResult);
273 STORM_LOG_ASSERT(
false,
"This point must not be reached, because then no pivot state could be found.");
277template<storm::dd::DdType Type,
typename ValueType>
278RefinementPredicates MenuGameRefiner<Type, ValueType>::derivePredicatesFromDifferingChoices(
storm::dd::Bdd<Type> const& player1Choice,
283 bool fromGuard =
false;
286 AbstractionInformation<Type>
const& abstractionInformation = abstractor.get().getAbstractionInformation();
290 auto pl1It = player1ChoiceAsAdd.
begin();
291 uint_fast64_t player1Index = abstractionInformation.decodePlayer1Choice((*pl1It).first, abstractionInformation.getPlayer1VariableCount());
295 bool buttomStateSuccessor =
296 !((abstractionInformation.getBottomStateBdd(
false,
false) && lowerChoice) || (abstractionInformation.getBottomStateBdd(
false,
false) && upperChoice))
301 if (buttomStateSuccessor) {
302 STORM_LOG_TRACE(
"One of the successors is a bottom state, taking a guard as a new predicate.");
303 newPredicate = abstractor.get().getGuard(player1Index);
305 STORM_LOG_DEBUG(
"Derived new predicate (based on guard): " << newPredicate);
307 STORM_LOG_TRACE(
"No bottom state successor. Deriving a new predicate using weakest precondition.");
310 std::map<uint64_t, std::pair<storm::storage::BitVector, ValueType>> lowerChoiceUpdateToSuccessorMapping =
311 abstractionInformation.template decodeChoiceToUpdateSuccessorMapping<ValueType>(lowerChoice);
312 std::map<uint64_t, std::pair<storm::storage::BitVector, ValueType>> upperChoiceUpdateToSuccessorMapping =
313 abstractionInformation.template decodeChoiceToUpdateSuccessorMapping<ValueType>(upperChoice);
315 lowerChoiceUpdateToSuccessorMapping.size() == upperChoiceUpdateToSuccessorMapping.size(),
316 "Mismatching sizes after decode (" << lowerChoiceUpdateToSuccessorMapping.size() <<
" vs. " << upperChoiceUpdateToSuccessorMapping.size() <<
").");
319 std::vector<std::pair<uint64_t, ValueType>> updateIndicesAndMasses;
320 for (
auto const& entry : lowerChoiceUpdateToSuccessorMapping) {
321 updateIndicesAndMasses.emplace_back(entry.first, entry.second.second);
323 std::sort(updateIndicesAndMasses.begin(), updateIndicesAndMasses.end(),
324 [](std::pair<uint64_t, ValueType>
const& a, std::pair<uint64_t, ValueType>
const& b) { return a.second > b.second; });
328 std::set<uint64_t> deviationPredicates;
329 uint64_t orderedUpdateIndex = 0;
330 std::vector<storm::expressions::Expression> possibleRefinementPredicates;
331 for (; orderedUpdateIndex < updateIndicesAndMasses.size(); ++orderedUpdateIndex) {
332 storm::storage::BitVector const& lower = lowerChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first;
333 storm::storage::BitVector const& upper = upperChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first;
335 bool deviates = lower != upper;
337 std::map<storm::expressions::Variable, storm::expressions::Expression> variableUpdates =
338 abstractor.get().getVariableUpdates(player1Index, updateIndicesAndMasses[orderedUpdateIndex].first);
340 for (uint64_t predicateIndex = 0; predicateIndex < lower.
size(); ++predicateIndex) {
341 if (lower[predicateIndex] != upper[predicateIndex]) {
342 possibleRefinementPredicates.push_back(
343 abstractionInformation.getPredicateByIndex(predicateIndex).substitute(variableUpdates).simplify());
344 if (!rankPredicates) {
353 STORM_LOG_ASSERT(!possibleRefinementPredicates.empty(),
"Expected refinement predicates.");
356 for (
auto const& pred : possibleRefinementPredicates) {
360 if (rankPredicates) {
364 std::vector<storm::expressions::Expression> otherRefinementPredicates;
365 for (; orderedUpdateIndex < updateIndicesAndMasses.size(); ++orderedUpdateIndex) {
366 storm::storage::BitVector
const& lower = lowerChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first;
367 storm::storage::BitVector
const& upper = upperChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first;
369 bool deviates = lower != upper;
371 std::map<storm::expressions::Variable, storm::expressions::Expression> newVariableUpdates =
372 abstractor.get().getVariableUpdates(player1Index, updateIndicesAndMasses[orderedUpdateIndex].first);
373 for (uint64_t predicateIndex = 0; predicateIndex < lower.
size(); ++predicateIndex) {
374 if (lower[predicateIndex] != upper[predicateIndex]) {
375 otherRefinementPredicates.push_back(
376 abstractionInformation.getPredicateByIndex(predicateIndex).substitute(newVariableUpdates).simplify());
383 std::vector<uint64_t> refinementPredicateIndexToCount(possibleRefinementPredicates.size(), 0);
384 for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) {
385 refinementPredicateIndexToCount[index] = 1;
387 for (
auto const& otherPredicate : otherRefinementPredicates) {
388 for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) {
389 if (equivalenceChecker.areEquivalentModuloNegation(otherPredicate, possibleRefinementPredicates[index])) {
390 ++refinementPredicateIndexToCount[index];
396 uint64_t chosenPredicateIndex = 0;
397 for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) {
398 if (refinementPredicateIndexToCount[index] > refinementPredicateIndexToCount[chosenPredicateIndex]) {
399 chosenPredicateIndex = index;
402 newPredicate = possibleRefinementPredicates[chosenPredicateIndex];
403 STORM_LOG_DEBUG(
"Derived new predicate (based on weakest-precondition): " << newPredicate <<
", (equivalent to "
404 << (refinementPredicateIndexToCount[chosenPredicateIndex] - 1)
405 <<
" other refinement predicates).");
407 newPredicate = possibleRefinementPredicates.front();
408 STORM_LOG_DEBUG(
"Derived new predicate (based on weakest-precondition): " << newPredicate <<
".");
414 return RefinementPredicates(fromGuard ? RefinementPredicates::Source::Guard : RefinementPredicates::Source::WeakestPrecondition, {newPredicate});
417template<storm::dd::DdType Type,
typename ValueType>
418RefinementPredicates MenuGameRefiner<Type, ValueType>::derivePredicatesFromChoice(storm::gbar::abstraction::MenuGame<Type, ValueType>
const& game,
419 storm::dd::Bdd<Type>
const& pivotState,
420 storm::dd::Bdd<Type>
const& player1Choice, storm::dd::Bdd<Type>
const& choice,
421 storm::dd::Bdd<Type>
const& choiceSuccessors)
const {
423 storm::expressions::Expression newPredicate;
424 bool fromGuard =
false;
427 AbstractionInformation<Type>
const& abstractionInformation = abstractor.get().getAbstractionInformation();
430 storm::dd::Add<Type, ValueType> player1ChoiceAsAdd = player1Choice.template toAdd<ValueType>();
431 auto pl1It = player1ChoiceAsAdd.
begin();
432 uint_fast64_t player1Index = abstractionInformation.decodePlayer1Choice((*pl1It).first, abstractionInformation.getPlayer1VariableCount());
436 bool buttomStateSuccessor = !((abstractionInformation.getBottomStateBdd(
false,
false) && choiceSuccessors)).isZero();
438 std::vector<storm::expressions::Expression> possibleRefinementPredicates;
442 if (buttomStateSuccessor) {
443 STORM_LOG_TRACE(
"One of the successors is a bottom state, taking a guard as a new predicate.");
444 possibleRefinementPredicates.emplace_back(abstractor.get().getGuard(player1Index));
446 STORM_LOG_DEBUG(
"Derived new predicate (based on guard): " << possibleRefinementPredicates.back());
448 STORM_LOG_TRACE(
"No bottom state successor. Deriving a new predicate using weakest precondition.");
451 std::map<uint64_t, std::pair<storm::storage::BitVector, ValueType>> choiceUpdateToSuccessorMapping =
452 abstractionInformation.template decodeChoiceToUpdateSuccessorMapping<ValueType>(choiceSuccessors);
453 std::vector<std::pair<uint64_t, ValueType>> sortedChoiceUpdateIndicesAndMasses;
454 for (
auto const& e : choiceUpdateToSuccessorMapping) {
455 sortedChoiceUpdateIndicesAndMasses.emplace_back(e.first, e.second.second);
457 std::sort(sortedChoiceUpdateIndicesAndMasses.begin(), sortedChoiceUpdateIndicesAndMasses.end(),
458 [](std::pair<uint64_t, ValueType>
const& a, std::pair<uint64_t, ValueType>
const& b) { return a.second > b.second; });
461 std::set<storm::expressions::Variable> variablesToAbstract = game.
getRowVariables();
464 storm::dd::Bdd<Type> otherChoices =
469 std::vector<std::map<uint64_t, std::pair<storm::storage::BitVector, ValueType>>> otherChoicesUpdateToSuccessorMappings =
470 abstractionInformation.template decodeChoicesToUpdateSuccessorMapping<ValueType>(game.
getPlayer2Variables(), otherChoices);
472 for (
auto const& otherChoice : otherChoicesUpdateToSuccessorMappings) {
473 for (uint64_t updateIndex = 0; updateIndex < sortedChoiceUpdateIndicesAndMasses.size(); ++updateIndex) {
474 storm::storage::BitVector
const& choiceSuccessor =
475 choiceUpdateToSuccessorMapping.at(sortedChoiceUpdateIndicesAndMasses[updateIndex].first).first;
476 storm::storage::BitVector
const& otherChoiceSuccessor = otherChoice.at(sortedChoiceUpdateIndicesAndMasses[updateIndex].first).first;
478 bool deviates = choiceSuccessor != otherChoiceSuccessor;
480 std::map<storm::expressions::Variable, storm::expressions::Expression> variableUpdates =
481 abstractor.get().getVariableUpdates(player1Index, sortedChoiceUpdateIndicesAndMasses[updateIndex].first);
483 for (uint64_t predicateIndex = 0; predicateIndex < choiceSuccessor.
size(); ++predicateIndex) {
484 if (choiceSuccessor[predicateIndex] != otherChoiceSuccessor[predicateIndex]) {
485 possibleRefinementPredicates.push_back(
486 abstractionInformation.getPredicateByIndex(predicateIndex).substitute(variableUpdates).simplify());
487 if (!rankPredicates) {
498 STORM_LOG_ASSERT(!possibleRefinementPredicates.empty(),
"Expected refinement predicates.");
501 for (
auto const& pred : possibleRefinementPredicates) {
506 return RefinementPredicates(fromGuard ? RefinementPredicates::Source::Guard : RefinementPredicates::Source::WeakestPrecondition,
507 {possibleRefinementPredicates});
510template<storm::dd::DdType Type,
typename ValueType>
536 constraint &= minPlayer2Strategy.
exclusiveOr(maxPlayer2Strategy);
544template<storm::dd::DdType Type,
typename ValueType>
545RefinementPredicates MenuGameRefiner<Type, ValueType>::derivePredicatesFromPivotState(
552 bool player1ChoicesDifferent = !(pivotState && minPlayer1Strategy).exclusiveOr(pivotState && maxPlayer1Strategy).isZero();
554 boost::optional<RefinementPredicates> predicates;
558 storm::dd::Bdd<Type> lowerChoice1 = (lowerChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract);
559 storm::dd::Bdd<Type> lowerChoice2 = (lowerChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract);
561 bool lowerChoicesDifferent = !lowerChoice1.
exclusiveOr(lowerChoice2).isZero() && !lowerChoice1.
isZero() && !lowerChoice2.
isZero();
562 if (lowerChoicesDifferent) {
564 if (this->addPredicatesEagerly) {
565 predicates = derivePredicatesFromChoice(game, pivotState, (pivotState && minPlayer1Strategy).existsAbstract(game.
getRowVariables()),
566 lowerChoice && minPlayer2Strategy, lowerChoice1);
569 derivePredicatesFromDifferingChoices((pivotState && minPlayer1Strategy).existsAbstract(game.
getRowVariables()), lowerChoice1, lowerChoice2);
573 if (predicates && !player1ChoicesDifferent) {
574 return predicates.get();
577 boost::optional<RefinementPredicates> additionalPredicates;
580 storm::dd::Bdd<Type> upperChoice1 = (upperChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract);
581 storm::dd::Bdd<Type> upperChoice2 = (upperChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract);
583 bool upperChoicesDifferent = !upperChoice1.
exclusiveOr(upperChoice2).isZero() && !upperChoice1.
isZero() && !upperChoice2.
isZero();
584 if (upperChoicesDifferent) {
586 if (this->addPredicatesEagerly) {
587 additionalPredicates = derivePredicatesFromChoice(game, pivotState, (pivotState && maxPlayer1Strategy).existsAbstract(game.
getRowVariables()),
588 upperChoice && maxPlayer2Strategy, upperChoice1);
590 additionalPredicates =
591 derivePredicatesFromDifferingChoices((pivotState && maxPlayer1Strategy).existsAbstract(game.
getRowVariables()), upperChoice1, upperChoice2);
595 if (additionalPredicates) {
596 if (additionalPredicates.get().getSource() == RefinementPredicates::Source::Guard) {
597 return additionalPredicates.get();
600 predicates = additionalPredicates;
602 predicates.get().addPredicates(additionalPredicates.get().getPredicates());
607 STORM_LOG_THROW(
static_cast<bool>(predicates), storm::exceptions::InvalidStateException,
"Could not derive predicates for refinement.");
609 return predicates.get();
612template<storm::dd::DdType Type,
typename ValueType>
613std::pair<std::vector<std::vector<storm::expressions::Expression>>, std::map<storm::expressions::Variable, storm::expressions::Expression>>
614MenuGameRefiner<Type, ValueType>::buildTrace(storm::expressions::ExpressionManager& expressionManager,
615 storm::gbar::abstraction::MenuGame<Type, ValueType>
const& game, storm::dd::Bdd<Type>
const& spanningTree,
616 storm::dd::Bdd<Type>
const& pivotState)
const {
617 std::vector<std::vector<storm::expressions::Expression>> predicates;
620 AbstractionInformation<Type>
const& abstractionInformation = abstractor.get().getAbstractionInformation();
621 std::set<storm::expressions::Variable> variablesToAbstract(game.
getColumnVariables());
625 storm::expressions::Expression initialExpression = abstractor.get().getInitialExpression();
627 std::set<storm::expressions::Variable> oldVariables = initialExpression.
getVariables();
628 for (
auto const& predicate : abstractionInformation.getPredicates()) {
629 std::set<storm::expressions::Variable> usedVariables = predicate.getVariables();
630 oldVariables.insert(usedVariables.begin(), usedVariables.end());
633 std::map<storm::expressions::Variable, storm::expressions::Variable> oldToNewVariables;
634 for (
auto const& variable : oldVariables) {
635 oldToNewVariables[variable] = expressionManager.
getVariable(variable.getName());
637 std::map<storm::expressions::Variable, storm::expressions::Expression> lastSubstitution;
638 for (
auto const& variable : oldToNewVariables) {
639 lastSubstitution[variable.second] = variable.second;
641 std::map<storm::expressions::Variable, storm::expressions::Expression> stepVariableToCopiedVariableMap;
644 storm::storage::BitVector decodedTargetState = abstractionInformation.decodeState(pivotState);
645 predicates.emplace_back(abstractionInformation.getPredicates(decodedTargetState));
646 for (
auto& predicate : predicates.back()) {
647 predicate = predicate.changeManager(expressionManager);
650 for (
auto const& pred : abstractionInformation.getConstraints()) {
651 predicates.back().push_back(pred.changeManager(expressionManager));
655 storm::dd::Bdd<Type> currentState = pivotState;
658 std::tuple<storm::storage::BitVector, uint64_t, uint64_t> decodedPredecessor =
659 abstractionInformation.decodeStatePlayer1ChoiceAndUpdate(predecessorTransition);
662 std::map<storm::expressions::Variable, storm::expressions::Expression> substitution;
663 for (
auto const& variablePair : oldToNewVariables) {
664 storm::expressions::Variable variableCopy = expressionManager.
declareVariableCopy(variablePair.second);
665 substitution[variablePair.second] = variableCopy;
666 stepVariableToCopiedVariableMap[variableCopy] = variablePair.second;
670 auto variableUpdates = abstractor.get().getVariableUpdates(std::get<1>(decodedPredecessor), std::get<2>(decodedPredecessor));
671 for (
auto const& oldNewVariablePair : oldToNewVariables) {
672 storm::expressions::Variable
const& newVariable = oldNewVariablePair.second;
675 auto updateIt = variableUpdates.find(oldNewVariablePair.first);
676 if (updateIt != variableUpdates.end()) {
677 auto const& update = *updateIt;
679 if (update.second.hasBooleanType()) {
680 predicates.back().push_back(
681 storm::expressions::iff(lastSubstitution.at(newVariable), update.second.changeManager(expressionManager).substitute(substitution)));
683 predicates.back().push_back(lastSubstitution.at(newVariable) == update.second.changeManager(expressionManager).substitute(substitution));
688 predicates.back().push_back(
storm::expressions::iff(lastSubstitution.at(newVariable), substitution.at(newVariable)));
690 predicates.back().push_back(lastSubstitution.at(newVariable) == substitution.at(newVariable));
696 predicates.back().push_back(abstractor.get().getGuard(std::get<1>(decodedPredecessor)).changeManager(expressionManager).substitute(substitution));
699 predicates.emplace_back(abstractionInformation.getPredicates(std::get<0>(decodedPredecessor)));
700 for (
auto& predicate : predicates.back()) {
701 predicate = predicate.changeManager(expressionManager).substitute(substitution);
704 for (
auto const& pred : abstractionInformation.getConstraints()) {
705 predicates.back().push_back(pred.changeManager(expressionManager).substitute(substitution));
708 lastSubstitution = std::move(substitution);
709 currentState = predecessorTransition.
existsAbstract(variablesToAbstract);
713 return std::make_pair(predicates, stepVariableToCopiedVariableMap);
716template<
typename ValueType>
719template<storm::dd::DdType Type,
typename ValueType>
720std::pair<std::vector<uint64_t>, std::vector<uint64_t>> MenuGameRefiner<Type, ValueType>::buildReversedLabeledPath(
722 std::pair<std::vector<uint64_t>, std::vector<uint64_t>> result;
723 result.first.emplace_back(pivotStateResult.
pivotState);
729 result.first.emplace_back(currentState);
730 result.second.emplace_back(currentAction);
731 currentAction = pivotStateResult.
predecessors[currentState].second;
732 currentState = pivotStateResult.
predecessors[currentState].first;
735 STORM_LOG_ASSERT(result.first.size() == result.second.size() + 1,
"Path size mismatch.");
739template<storm::dd::DdType Type,
typename ValueType>
740std::pair<std::vector<std::vector<storm::expressions::Expression>>, std::map<storm::expressions::Variable, storm::expressions::Expression>>
742 std::vector<uint64_t>
const& reversedPath, std::vector<uint64_t>
const& reversedLabels,
743 storm::dd::Odd const& odd, std::vector<uint64_t>
const* stateToOffset)
const {
744 STORM_LOG_ASSERT(reversedPath.size() == reversedLabels.size() + 1,
"Path size mismatch.");
746 std::vector<std::vector<storm::expressions::Expression>> predicates;
748 AbstractionInformation<Type>
const& abstractionInformation = abstractor.get().getAbstractionInformation();
751 std::set<storm::expressions::Variable> oldVariables = initialExpression.
getVariables();
752 for (
auto const& predicate : abstractionInformation.getPredicates()) {
753 std::set<storm::expressions::Variable> usedVariables = predicate.getVariables();
754 oldVariables.insert(usedVariables.begin(), usedVariables.end());
757 std::map<storm::expressions::Variable, storm::expressions::Variable> oldToNewVariables;
758 for (
auto const& variable : oldVariables) {
759 oldToNewVariables[variable] = expressionManager.
getVariable(variable.getName());
761 std::map<storm::expressions::Variable, storm::expressions::Expression> currentSubstitution;
762 for (
auto const& variable : oldToNewVariables) {
763 currentSubstitution[variable.second] = variable.second;
765 std::map<storm::expressions::Variable, storm::expressions::Expression> stepVariableToCopiedVariableMap;
767 auto pathIt = reversedPath.rbegin();
773 uint64_t predicateValuationOffset = abstractionInformation.getNumberOfDdSourceLocationVariables() + 1;
774 storm::storage::BitVector extendedPredicateValuation =
775 odd.
getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + predicateValuationOffset);
779 predicates.emplace_back(abstractionInformation.getPredicatesExcludingBottom(extendedPredicateValuation));
780 for (
auto& predicate : predicates.back()) {
781 predicate = predicate.changeManager(expressionManager);
785 for (
auto const& pred : abstractionInformation.getConstraints()) {
786 predicates.back().push_back(pred.changeManager(expressionManager));
790 predicates.back().push_back(initialExpression.
changeManager(expressionManager));
793 auto actionIt = reversedLabels.
rbegin();
794 for (; pathIt != reversedPath.rend(); ++pathIt) {
796 predicates.emplace_back();
799 predicates.back().emplace_back(abstractor.get().getGuard(*actionIt).changeManager(expressionManager).substitute(currentSubstitution));
802 std::set<storm::expressions::Variable>
const& assignedVariables = abstractor.get().getAssignedVariables(*actionIt);
805 std::map<storm::expressions::Variable, storm::expressions::Variable> newVariableMaps;
806 for (
auto const& variable : assignedVariables) {
807 storm::expressions::Variable variableCopy = expressionManager.
declareVariableCopy(variable);
808 newVariableMaps[oldToNewVariables.at(variable)] = variableCopy;
809 stepVariableToCopiedVariableMap[variableCopy] = variable;
813 auto variableUpdateVector = abstractor.get().getVariableUpdates(*actionIt);
816 storm::expressions::Expression allVariableUpdateExpression;
817 for (
auto const& variableUpdates : variableUpdateVector) {
818 storm::expressions::Expression variableUpdateExpression;
819 for (
auto const& update : variableUpdates) {
820 if (update.second.hasBooleanType()) {
821 variableUpdateExpression =
823 update.second.changeManager(expressionManager).substitute(currentSubstitution));
825 variableUpdateExpression = variableUpdateExpression && newVariableMaps.at(update.first) ==
830 allVariableUpdateExpression = allVariableUpdateExpression || variableUpdateExpression;
833 allVariableUpdateExpression = expressionManager.
boolean(
true);
835 predicates.back().emplace_back(allVariableUpdateExpression);
838 for (
auto const& variablePair : newVariableMaps) {
839 currentSubstitution[variablePair.first] = variablePair.second;
843 extendedPredicateValuation =
844 odd.
getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + predicateValuationOffset);
848 for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.getNumberOfPredicates(); ++predicateIndex) {
849 auto const& predicate = abstractionInformation.getPredicateByIndex(predicateIndex);
850 std::set<storm::expressions::Variable> usedVariables = predicate.getVariables();
852 bool containsAssignedVariables =
false;
853 for (
auto usedIt = usedVariables.begin(), assignedIt = assignedVariables.begin();;) {
854 if (usedIt == usedVariables.end() || assignedIt == assignedVariables.end()) {
858 if (*usedIt == *assignedIt) {
859 containsAssignedVariables =
true;
863 if (*usedIt < *assignedIt) {
870 if (containsAssignedVariables) {
871 auto transformedPredicate = predicate.changeManager(expressionManager).substitute(currentSubstitution);
872 predicates.back().emplace_back(extendedPredicateValuation.
get(predicateIndex + predicateValuationOffset) ? transformedPredicate
873 : !transformedPredicate);
878 for (
auto const& constraint : abstractionInformation.getConstraints()) {
879 std::set<storm::expressions::Variable> usedVariables = constraint.getVariables();
881 bool containsAssignedVariables =
false;
882 for (
auto usedIt = usedVariables.begin(), assignedIt = assignedVariables.begin();;) {
883 if (usedIt == usedVariables.end() || assignedIt == assignedVariables.end()) {
887 if (*usedIt == *assignedIt) {
888 containsAssignedVariables =
true;
892 if (*usedIt < *assignedIt) {
899 if (containsAssignedVariables) {
900 auto transformedConstraint = constraint.changeManager(expressionManager).substitute(currentSubstitution);
901 predicates.back().emplace_back(transformedConstraint);
908 return std::make_pair(predicates, stepVariableToCopiedVariableMap);
911template<storm::dd::DdType Type,
typename ValueType>
912boost::optional<RefinementPredicates> MenuGameRefiner<Type, ValueType>::derivePredicatesFromInterpolationFromTrace(
913 storm::expressions::ExpressionManager& interpolationManager, std::vector<std::vector<storm::expressions::Expression>>
const& trace,
914 std::map<storm::expressions::Variable, storm::expressions::Expression>
const& variableSubstitution)
const {
915 AbstractionInformation<Type>
const& abstractionInformation = abstractor.get().getAbstractionInformation();
917 auto start = std::chrono::high_resolution_clock::now();
918 boost::optional<RefinementPredicates> predicates;
921 auto assertionStart = std::chrono::high_resolution_clock::now();
922 storm::solver::MathsatSmtSolver interpolatingSolver(interpolationManager, storm::solver::MathsatSmtSolver::Options(
true,
false,
true));
923 uint64_t stepCounter = 0;
924 for (
auto const& traceElement : trace) {
927 interpolatingSolver.setInterpolationGroup(stepCounter);
928 for (
auto const& predicate : traceElement) {
929 interpolatingSolver.add(predicate);
934 auto assertionEnd = std::chrono::high_resolution_clock::now();
935 STORM_LOG_TRACE(
"Asserting trace formula took " << std::chrono::duration_cast<std::chrono::milliseconds>(assertionEnd - assertionStart).
count() <<
"ms.");
940 STORM_LOG_TRACE(
"Trace formula is unsatisfiable. Starting interpolation.");
942 std::vector<storm::expressions::Expression> interpolants;
943 std::vector<uint64_t> prefix;
944 for (uint64_t step = 0; step < stepCounter; ++step) {
945 prefix.push_back(step);
946 storm::expressions::Expression interpolant =
947 interpolatingSolver.getInterpolant(prefix).substitute(variableSubstitution).changeManager(abstractionInformation.getExpressionManager());
950 STORM_LOG_TRACE(
"Trace formula became unsatisfiable at position " << step <<
" of " << stepCounter <<
".");
953 if (!interpolant.
isTrue()) {
954 STORM_LOG_DEBUG(
"Derived new predicate (based on interpolation at step " << step <<
" out of " << stepCounter <<
"): " << interpolant);
955 interpolants.push_back(interpolant);
959 STORM_LOG_ASSERT(!interpolants.empty(),
"Expected to have non-empty set of interpolants.");
961 predicates = boost::make_optional(RefinementPredicates(RefinementPredicates::Source::Interpolation, interpolants));
963 STORM_LOG_TRACE(
"Trace formula is satisfiable, not using interpolation.");
965 auto end = std::chrono::high_resolution_clock::now();
968 STORM_LOG_TRACE(
"Deriving predicates using interpolation from witness of size "
969 << trace.size() <<
" took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() <<
"ms.");
971 STORM_LOG_TRACE(
"Tried deriving predicates using interpolation but failed in "
972 << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).
count() <<
"ms.");
978template<storm::dd::DdType Type,
typename ValueType>
979boost::optional<RefinementPredicates> MenuGameRefiner<Type, ValueType>::derivePredicatesFromInterpolation(
980 storm::gbar::abstraction::MenuGame<Type, ValueType>
const& game, SymbolicPivotStateResult<Type, ValueType>
const& symbolicPivotStateResult,
981 storm::dd::Bdd<Type>
const& minPlayer1Strategy, storm::dd::Bdd<Type>
const& minPlayer2Strategy, storm::dd::Bdd<Type>
const& maxPlayer1Strategy,
982 storm::dd::Bdd<Type>
const& maxPlayer2Strategy)
const {
984 SymbolicMostProbablePathsResult<Type, ValueType> symbolicMostProbablePathsResult;
985 if (!symbolicPivotStateResult.symbolicMostProbablePathsResult) {
986 symbolicMostProbablePathsResult =
getMostProbablePathSpanningTree(game, symbolicPivotStateResult.fromDirection == storm::OptimizationDirection::Minimize
987 ? minPlayer1Strategy && minPlayer2Strategy
988 : maxPlayer1Strategy && maxPlayer2Strategy);
990 symbolicMostProbablePathsResult = symbolicPivotStateResult.symbolicMostProbablePathsResult.get();
994 AbstractionInformation<Type>
const& abstractionInformation = abstractor.get().getAbstractionInformation();
995 std::shared_ptr<storm::expressions::ExpressionManager> interpolationManager = abstractionInformation.getExpressionManager().
clone();
998 auto start = std::chrono::high_resolution_clock::now();
999 std::pair<std::vector<std::vector<storm::expressions::Expression>>, std::map<storm::expressions::Variable, storm::expressions::Expression>>
1000 traceAndVariableSubstitution =
1001 buildTrace(*interpolationManager, game, symbolicMostProbablePathsResult.spanningTree, symbolicPivotStateResult.pivotState);
1002 auto end = std::chrono::high_resolution_clock::now();
1003 STORM_LOG_DEBUG(
"Building the trace and variable substitution for interpolation from symbolic most-probable paths result took "
1004 << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).
count() <<
"ms.");
1006 return derivePredicatesFromInterpolationFromTrace(*interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second);
1009template<storm::dd::DdType Type,
typename ValueType>
1010boost::optional<RefinementPredicates> MenuGameRefiner<Type, ValueType>::derivePredicatesFromInterpolation(
1011 storm::gbar::abstraction::MenuGame<Type, ValueType>
const& , ExplicitPivotStateResult<ValueType>
const& pivotStateResult,
1012 storm::dd::Odd
const& odd)
const {
1015 AbstractionInformation<Type>
const& abstractionInformation = abstractor.get().getAbstractionInformation();
1016 std::shared_ptr<storm::expressions::ExpressionManager> interpolationManager = abstractionInformation.getExpressionManager().clone();
1019 auto start = std::chrono::high_resolution_clock::now();
1020 std::pair<std::vector<uint64_t>, std::vector<uint64_t>> labeledReversedPath = buildReversedLabeledPath(pivotStateResult);
1023 if (labeledReversedPath.first.size() == 1) {
1027 std::pair<std::vector<std::vector<storm::expressions::Expression>>, std::map<storm::expressions::Variable, storm::expressions::Expression>>
1028 traceAndVariableSubstitution = buildTraceFromReversedLabeledPath(*interpolationManager, labeledReversedPath.first, labeledReversedPath.second, odd);
1029 auto end = std::chrono::high_resolution_clock::now();
1030 STORM_LOG_DEBUG(
"Building the trace and variable substitution for interpolation from explicit most-probable paths result took "
1031 << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).
count() <<
"ms.");
1033 return derivePredicatesFromInterpolationFromTrace(*interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second);
1036template<storm::dd::DdType Type,
typename ValueType>
1048 auto oldMinPlayer1Strategy = minPlayer1Strategy;
1049 minPlayer1Strategy = (maxPlayer1Strategy && qualitativeResult.
prob0Min.getPlayer2States())
1051 .ite(maxPlayer1Strategy, minPlayer1Strategy);
1055 computePivotStates(game, transitionMatrixBdd, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1071 boost::optional<RefinementPredicates> predicates;
1072 if (useInterpolation) {
1074 derivePredicatesFromInterpolation(game, symbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1079 predicates = derivePredicatesFromPivotState(game, symbolicPivotStateResult.
pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy,
1080 maxPlayer2Strategy);
1082 STORM_LOG_THROW(
static_cast<bool>(predicates), storm::exceptions::InvalidStateException,
"Predicates needed to continue.");
1085 std::vector<storm::expressions::Expression> preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource());
1086 performRefinement(createGlobalRefinement(preparedPredicates));
1090template<
typename ValueType>
1101template<
typename ValueType>
1124template<
typename ValueType>
1126 bool probabilityDistances, std::vector<ValueType>& distances, std::vector<std::pair<uint64_t, uint64_t>>& predecessors,
1127 bool generatePredecessors,
bool lower, uint64_t currentState, ValueType
const& currentDistance, [[maybe_unused]]
bool isPivotState,
1135 STORM_LOG_ASSERT(isPivotState || !otherStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) ||
1137 "Did not expect deviation in player 2 strategy.");
1138 STORM_LOG_ASSERT(player2Grouping[player2Successor] <= player2Choice && player2Choice < player2Grouping[player2Successor + 1],
1139 "Illegal choice for player 2.");
1141 for (
auto const& entry : transitionMatrix.
getRow(player2Choice)) {
1142 uint64_t player1Successor = entry.getColumn();
1143 if (!relevantStates.
get(player1Successor)) {
1147 ValueType alternateDistance;
1148 if (probabilityDistances) {
1149 alternateDistance = currentDistance * entry.getValue();
1153 if (probabilityDistances ? alternateDistance > distances[player1Successor] : alternateDistance < distances[player1Successor]) {
1154 distances[player1Successor] = alternateDistance;
1155 if (generatePredecessors) {
1156 predecessors[player1Successor] = std::make_pair(currentState, player1Labeling[player2Successor]);
1158 dijkstraQueue.emplace(alternateDistance, player1Successor, lower);
1162 STORM_LOG_ASSERT(targetStates.get(currentState),
"Expecting min strategy for non-target states.");
1166template<
typename ValueType>
1172 std::vector<ValueType>
const* upperValues =
nullptr) {
1174 STORM_LOG_ASSERT(!lowerValues || upperValues,
"Expected none or both value results.");
1175 STORM_LOG_ASSERT(!upperValues || lowerValues,
"Expected none or both value results.");
1183 uint64_t numberOfStates = initialStates.
size();
1187 ValueType unreachableDistance =
1192 std::vector<ValueType> lowerDistances(numberOfStates, unreachableDistance);
1193 std::vector<std::pair<uint64_t, uint64_t>> lowerPredecessors;
1194 std::vector<ValueType> upperDistances(numberOfStates, unreachableDistance);
1195 std::vector<std::pair<uint64_t, uint64_t>> upperPredecessors;
1197 if (generatePredecessors) {
1198 lowerPredecessors.resize(numberOfStates,
1200 upperPredecessors.resize(numberOfStates,
1207 for (uint64_t initialState : initialStates) {
1208 if (!relevantStates.
get(initialState)) {
1212 lowerDistances[initialState] = zeroDistance;
1213 upperDistances[initialState] = zeroDistance;
1214 dijkstraQueue.emplace(zeroDistance, initialState,
true);
1215 dijkstraQueue.emplace(zeroDistance, initialState,
false);
1221 lowerValues && upperValues;
1222 bool foundPivotState =
false;
1228 while (!dijkstraQueue.empty()) {
1230 auto currentDijkstraElement = *dijkstraQueue.begin();
1231 ValueType currentDistance = currentDijkstraElement.distance;
1232 uint64_t currentState = currentDijkstraElement.state;
1233 bool currentLower = currentDijkstraElement.lower;
1234 dijkstraQueue.erase(dijkstraQueue.begin());
1236 if (foundPivotState && (probabilityDistances ? currentDistance < pivotState.distance : currentDistance > pivotState.
distance)) {
1243 pivotState.
lower ? std::move(lowerPredecessors) : std::move(upperPredecessors));
1244 }
else if (pivotStateDeviation >= currentDistance) {
1248 pivotState.
lower ? std::move(lowerPredecessors) : std::move(upperPredecessors));
1253 bool isPivotState =
false;
1259 isPivotState =
true;
1267 isPivotState =
true;
1273 if (considerDeviation && foundPivotState) {
1274 ValueType deviationOfCurrentState = (*upperValues)[currentState] - (*lowerValues)[currentState];
1276 if (deviationOfCurrentState > pivotStateDeviation) {
1277 pivotState = currentDijkstraElement;
1278 pivotStateDeviation = deviationOfCurrentState;
1281 pivotStateDeviation *= currentDistance;
1284 }
else if (!foundPivotState) {
1285 pivotState = currentDijkstraElement;
1286 foundPivotState =
true;
1290 if (!considerDeviation) {
1292 pivotState.
lower ? std::move(lowerPredecessors) : std::move(upperPredecessors));
1297 if (!lowerValues || !upperValues || (*lowerValues)[currentState] < (*upperValues)[currentState]) {
1299 performDijkstraStep(dijkstraQueue, probabilityDistances, lowerDistances, lowerPredecessors, generatePredecessors,
true, currentState,
1300 currentDistance, isPivotState, minStrategyPair, maxStrategyPair, player1Labeling, player2Grouping, transitionMatrix,
1301 targetStates, relevantStates);
1303 performDijkstraStep(dijkstraQueue, probabilityDistances, upperDistances, upperPredecessors, generatePredecessors,
false, currentState,
1304 currentDistance, isPivotState, maxStrategyPair, minStrategyPair, player1Labeling, player2Grouping, transitionMatrix,
1305 targetStates, relevantStates);
1310 if (foundPivotState) {
1312 pivotState.
lower ? std::move(lowerPredecessors) : std::move(upperPredecessors));
1317 STORM_LOG_TRACE(
"Did not find pivot state in explicit Dijkstra search.");
1321template<storm::dd::DdType Type,
typename ValueType>
1322boost::optional<RefinementPredicates> MenuGameRefiner<Type, ValueType>::derivePredicatesFromInterpolationReversedPath(
1324 std::vector<uint64_t>
const& stateToOffset, std::vector<uint64_t>
const& reversedLabels)
const {
1326 auto start = std::chrono::high_resolution_clock::now();
1327 std::pair<std::vector<std::vector<storm::expressions::Expression>>, std::map<storm::expressions::Variable, storm::expressions::Expression>>
1328 traceAndVariableSubstitution = buildTraceFromReversedLabeledPath(interpolationManager, reversedPath, reversedLabels, odd, &stateToOffset);
1329 auto end = std::chrono::high_resolution_clock::now();
1330 STORM_LOG_DEBUG(
"Building the trace and variable substitution for interpolation from explicit most-probable paths result took "
1331 << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() <<
"ms.");
1333 return derivePredicatesFromInterpolationFromTrace(interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second);
1336template<storm::dd::DdType Type,
typename ValueType>
1339 [[maybe_unused]] std::vector<uint64_t>
const& player1Grouping, std::vector<uint64_t>
const& player1Labeling,
1346 (void)constraintStates;
1351 boost::optional<ExplicitPivotStateResult<ValueType>> optionalPivotStateResult =
1352 pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Labeling, initialStates, relevantStates, targetStates,
1353 minStrategyPair, maxStrategyPair);
1356 if (!optionalPivotStateResult) {
1362 auto const& pivotStateResult = optionalPivotStateResult.get();
1363 STORM_LOG_TRACE(
"Found pivot state " << pivotStateResult.pivotState <<
" with distance " << pivotStateResult.distance <<
".");
1366 auto const& abstractionInformation = abstractor.get().getAbstractionInformation();
1367 uint64_t pivotState = pivotStateResult.pivotState;
1375 STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1],
"Illegal choice for player 1.");
1376 minPlayer1Strategy |=
1377 symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount());
1381 minPlayer2Strategy |=
1382 minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.
getPlayer2Variables().size());
1386 maxPlayer2Strategy |=
1387 minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.
getPlayer2Variables().size());
1392 STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1],
"Illegal choice for player 1.");
1393 maxPlayer1Strategy |=
1394 symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount());
1398 minPlayer2Strategy |=
1399 maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.
getPlayer2Variables().size());
1403 maxPlayer2Strategy |=
1404 maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.
getPlayer2Variables().size());
1407 boost::optional<RefinementPredicates> predicates;
1408 if (useInterpolation) {
1409 predicates = derivePredicatesFromInterpolation(game, pivotStateResult, odd);
1412 predicates = derivePredicatesFromPivotState(game, symbolicPivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1414 STORM_LOG_THROW(
static_cast<bool>(predicates), storm::exceptions::InvalidStateException,
"Predicates needed to continue.");
1416 std::vector<storm::expressions::Expression> preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource());
1417 performRefinement(createGlobalRefinement(preparedPredicates));
1421template<storm::dd::DdType Type,
typename ValueType>
1424 [[maybe_unused]] std::vector<uint64_t>
const& player1Grouping, std::vector<uint64_t>
const& player1Labeling,
1431 (void)constraintStates;
1436 boost::optional<ExplicitPivotStateResult<ValueType>> optionalPivotStateResult =
1437 pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Labeling, initialStates, relevantStates, targetStates,
1438 minStrategyPair, maxStrategyPair, &quantitativeResult.
getMin().getValues(), &quantitativeResult.
getMax().getValues());
1440 STORM_LOG_THROW(optionalPivotStateResult, storm::exceptions::InvalidStateException,
"Did not find pivot state to proceed.");
1443 auto const& pivotStateResult = optionalPivotStateResult.get();
1444 STORM_LOG_TRACE(
"Found pivot state " << pivotStateResult.pivotState <<
" with distance " << pivotStateResult.distance <<
".");
1447 auto const& abstractionInformation = abstractor.get().getAbstractionInformation();
1448 uint64_t pivotState = pivotStateResult.pivotState;
1456 STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1],
"Illegal choice for player 1.");
1457 minPlayer1Strategy |=
1458 symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount());
1462 minPlayer2Strategy |=
1463 minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.
getPlayer2Variables().size());
1467 maxPlayer2Strategy |=
1468 minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.
getPlayer2Variables().size());
1473 STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1],
"Illegal choice for player 1.");
1474 maxPlayer1Strategy |=
1475 symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount());
1479 minPlayer2Strategy |=
1480 maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.
getPlayer2Variables().size());
1484 maxPlayer2Strategy |=
1485 maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.
getPlayer2Variables().size());
1489 boost::optional<RefinementPredicates> predicates;
1490 if (useInterpolation) {
1491 predicates = derivePredicatesFromInterpolation(game, pivotStateResult, odd);
1494 predicates = derivePredicatesFromPivotState(game, symbolicPivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1496 STORM_LOG_THROW(
static_cast<bool>(predicates), storm::exceptions::InvalidStateException,
"Predicates needed to continue.");
1498 std::vector<storm::expressions::Expression> preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource());
1499 performRefinement(createGlobalRefinement(preparedPredicates));
1503template<storm::dd::DdType Type,
typename ValueType>
1515 computePivotStates(game, transitionMatrixBdd, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1523 boost::optional<RefinementPredicates> predicates;
1524 if (useInterpolation) {
1526 derivePredicatesFromInterpolation(game, symbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy);
1531 predicates = derivePredicatesFromPivotState(game, symbolicPivotStateResult.
pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy,
1532 maxPlayer2Strategy);
1534 STORM_LOG_THROW(
static_cast<bool>(predicates), storm::exceptions::InvalidStateException,
"Predicates needed to continue.");
1536 std::vector<storm::expressions::Expression> preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource());
1537 performRefinement(createGlobalRefinement(preparedPredicates));
1542 std::size_t
operator()(std::set<storm::expressions::Variable>
const& set)
const {
1547template<storm::dd::DdType Type,
typename ValueType>
1548std::vector<storm::expressions::Expression> MenuGameRefiner<Type, ValueType>::preprocessPredicates(
1549 std::vector<storm::expressions::Expression>
const& predicates, RefinementPredicates::Source
const& source)
const {
1550 bool split = source == RefinementPredicates::Source::WeakestPrecondition && splitPredicates;
1551 split |= source == RefinementPredicates::Source::Interpolation && splitPredicates;
1555 auto start = std::chrono::high_resolution_clock::now();
1556 AbstractionInformation<Type>
const& abstractionInformation = abstractor.get().getAbstractionInformation();
1557 std::vector<storm::expressions::Expression> cleanedAtoms;
1559 std::unordered_map<std::set<storm::expressions::Variable>, std::vector<storm::expressions::Expression>, VariableSetHash> predicateClasses;
1561 for (
auto const& predicate : predicates) {
1563 std::vector<storm::expressions::Expression> atoms = splitter.split(predicate);
1566 for (
auto const& atom : atoms) {
1567 std::set<storm::expressions::Variable> vars = atom.getVariables();
1568 predicateClasses[vars].push_back(atom);
1573 uint64_t checkCounter = 0;
1574 for (
auto& predicateClass : predicateClasses) {
1575 std::vector<storm::expressions::Expression> cleanedAtomsOfClass;
1577 for (
auto const& predicate : predicateClass.second) {
1578 bool addPredicate =
true;
1579 for (
auto const& atom : cleanedAtomsOfClass) {
1580 if (predicate.areSame(atom)) {
1581 addPredicate =
false;
1586 if (equivalenceChecker.areEquivalentModuloNegation(predicate, atom)) {
1587 addPredicate =
false;
1592 cleanedAtomsOfClass.push_back(predicate);
1596 predicateClass.second = std::move(cleanedAtomsOfClass);
1599 std::unordered_map<std::set<storm::expressions::Variable>, std::vector<storm::expressions::Expression>, VariableSetHash> oldPredicateClasses;
1600 for (
auto const& oldPredicate : abstractionInformation.getPredicates()) {
1601 std::set<storm::expressions::Variable> vars = oldPredicate.getVariables();
1603 oldPredicateClasses[vars].push_back(oldPredicate);
1606 for (
auto const& predicateClass : predicateClasses) {
1607 auto oldPredicateClassIt = oldPredicateClasses.find(predicateClass.first);
1608 if (oldPredicateClassIt != oldPredicateClasses.end()) {
1609 for (
auto const& newAtom : predicateClass.second) {
1610 bool addAtom =
true;
1611 for (
auto const& oldPredicate : oldPredicateClassIt->second) {
1612 if (newAtom.areSame(oldPredicate)) {
1617 if (equivalenceChecker.areEquivalentModuloNegation(newAtom, oldPredicate)) {
1623 cleanedAtoms.push_back(newAtom);
1627 cleanedAtoms.insert(cleanedAtoms.end(), predicateClass.second.begin(), predicateClass.second.end());
1630 auto end = std::chrono::high_resolution_clock::now();
1631 STORM_LOG_TRACE(
"Preprocessing predicates took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).
count() <<
"ms (" << checkCounter
1634 return cleanedAtoms;
1642template<storm::dd::DdType Type,
typename ValueType>
1643std::vector<RefinementCommand> MenuGameRefiner<Type, ValueType>::createGlobalRefinement(std::vector<storm::expressions::Expression>
const& predicates)
const {
1644 std::vector<RefinementCommand> commands;
1645 commands.emplace_back(predicates);
1649template<storm::dd::DdType Type,
typename ValueType>
1650void MenuGameRefiner<Type, ValueType>::performRefinement(std::vector<RefinementCommand>
const& refinementCommands,
bool allowInjection)
const {
1651 if (!refinementPredicatesToInject.empty() && allowInjection) {
1654 for (
auto const& predicate : refinementPredicatesToInject.back()) {
1658 abstractor.get().refine(RefinementCommand(refinementPredicatesToInject.back()));
1659 refinementPredicatesToInject.pop_back();
1661 for (
auto const& command : refinementCommands) {
1662 STORM_LOG_INFO(
"Refining with " << command.getPredicates().size() <<
" predicates.");
1663 for (
auto const& predicate : command.getPredicates()) {
1666 if (!command.getPredicates().empty()) {
1667 abstractor.get().refine(command);
1673 for (
auto const& predicate : abstractor.get().getAbstractionInformation().getPredicates()) {
1678template<storm::dd::DdType Type,
typename ValueType>
1680 return addedAllGuardsFlag;
ValueType getMax() const
Retrieves the highest function value of any encoding.
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...
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...
Add< LibraryType, ValueType > maxAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Max-abstracts from the given meta variables.
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...
Add< LibraryType, ValueType > sumAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Sum-abstracts from the given meta variables.
Bdd< LibraryType > toBdd() const
Converts the ADD to a BDD by mapping all values unequal to zero to 1.
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...
Bdd< LibraryType > existsAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Existentially abstracts from the given meta variables.
bool isZero() const
Retrieves whether this DD represents the constant zero function.
virtual uint_fast64_t getNonZeroCount() const override
Retrieves the number of encodings that are mapped to a non-zero value.
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.
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.
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...
Bdd< LibraryType > ite(Bdd< LibraryType > const &thenBdd, Bdd< LibraryType > const &elseBdd) const
Performs an if-then-else with the given operands, i.e.
Bdd< LibraryType > exclusiveOr(Bdd< LibraryType > const &other) const
Performs a logical exclusive-or of the current and the given BDD.
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.
uint_fast64_t getTotalOffset() const
Retrieves the total offset, i.e., the sum of the then- and else-offset.
storm::storage::BitVector getEncoding(uint64_t offset, uint64_t variableCount=0) const
Retrieves the encoding for the given offset.
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.
virtual storm::storage::BitVector const & getStates() const =0
ExplicitQualitativeResult const & getProb0Max() const
ExplicitQualitativeResult const & getProb1Min() const
ExplicitQualitativeResult const & getProb1Max() const
ExplicitQualitativeResult const & getProb0Min() const
ExplicitQuantitativeResult< ValueType > const & getMin() const
ExplicitQuantitativeResult< ValueType > const & getMax() const
RefinementPredicates()=default
void addPredicates(std::vector< storm::expressions::Expression > const &newPredicates)
std::vector< storm::expressions::Expression > const & getPredicates() const
SymbolicQualitativeGameResult< Type > prob0Min
SymbolicQualitativeGameResult< Type > prob1Max
SymbolicQuantitativeGameResult< Type, ValueType > max
SymbolicQuantitativeGameResult< Type, ValueType > min
storm::dd::DdManager< Type > & getManager() const
Retrieves the manager responsible for the DDs that represent this model.
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...
storm::dd::Bdd< Type > const & getInitialStates() const
Retrieves the initial states of the model.
std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > const & getRowColumnMetaVariablePairs() const
Retrieves the pairs of row and column meta variables.
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.
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.
CheckResult
possible check results
A bit vector that is internally represented as a vector of 64-bit values.
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
ExplicitGameStrategy & getPlayer1Strategy()
ExplicitGameStrategy & getPlayer2Strategy()
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)
#define STORM_LOG_DEBUG(message)
#define STORM_LOG_TRACE(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
Expression iff(Expression const &first, Expression const &second)
SymbolicPivotStateResult< Type, ValueType > pickPivotState(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)
@ NearestMaximalDeviation
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 ¤tDistance, 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)
TargetType convertNumber(SourceType const &number)
solver::OptimizationDirection OptimizationDirection
Options that configure the game-based abstraction-refinement procedure.
bool addAllGuards
A flag indicating whether all guards are added as initial predicates.
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.
std::vector< std::pair< uint64_t, uint64_t > > predecessors
The predecessors for the states to obtain the given distance.
storm::dd::Bdd< Type > reachableTransitionsMin
storm::dd::Bdd< Type > reachableTransitionsMax
storm::dd::Bdd< Type > pivotStates
SymbolicMostProbablePathsResult()=default
storm::dd::Bdd< Type > spanningTree
storm::dd::Add< Type, ValueType > maxProbabilities
boost::optional< SymbolicMostProbablePathsResult< Type, ValueType > > symbolicMostProbablePathsResult
SymbolicPivotStateResult(storm::dd::Bdd< Type > const &pivotState, storm::OptimizationDirection fromDirection, boost::optional< SymbolicMostProbablePathsResult< Type, ValueType > > const &symbolicMostProbablePathsResult=boost::none)
storm::OptimizationDirection fromDirection
storm::dd::Bdd< Type > pivotState
std::size_t operator()(std::set< storm::expressions::Variable > const &set) const