|
|
@ -1004,7 +1004,19 @@ namespace storm { |
|
|
|
return getUsedLabelSet(context, solver.get_model(), variableInformation); |
|
|
|
} |
|
|
|
|
|
|
|
static void analyzeBadSolution(z3::context& context, z3::solver& solver, storm::models::Mdp<T> const& subMdp, storm::models::Mdp<T> const& originalMdp, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::set<uint_fast64_t> const& commandSet, VariableInformation& variableInformation, RelevancyInformation const& relevancyInformation) { |
|
|
|
/*! |
|
|
|
* Analyzes the given sub-MDP that has a maximal reachability of zero (i.e. no psi states are reachable) and tries to construct assertions that aim to make at least one psi state reachable. |
|
|
|
* |
|
|
|
* @param context The Z3 context in which to build the expressions. |
|
|
|
* @param solver The solver to use for the satisfiability evaluation. |
|
|
|
* @param subMdp The sub-MDP resulting from restricting the original MDP to the given command set. |
|
|
|
* @param originalMdp The original MDP. |
|
|
|
* @param phiStates A bit vector characterizing all phi states in the model. |
|
|
|
* @param psiState A bit vector characterizing all psi states in the model. |
|
|
|
* @param commandSet The currently chosen set of commands. |
|
|
|
* @param variableInformation A structure with information about the variables of the solver. |
|
|
|
*/ |
|
|
|
static void analyzeZeroProbabilitySolution(z3::context& context, z3::solver& solver, storm::models::Mdp<T> const& subMdp, storm::models::Mdp<T> const& originalMdp, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::set<uint_fast64_t> const& commandSet, VariableInformation& variableInformation, RelevancyInformation const& relevancyInformation) { |
|
|
|
storm::storage::BitVector reachableStates(subMdp.getNumberOfStates()); |
|
|
|
|
|
|
|
// Initialize the stack for the DFS. |
|
|
@ -1108,6 +1120,110 @@ namespace storm { |
|
|
|
assertDisjunction(context, solver, formulae); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Analyzes the given sub-MDP that has a maximal reachability of zero (i.e. no psi states are reachable) and tries to construct assertions that aim to make at least one psi state reachable. |
|
|
|
* |
|
|
|
* @param context The Z3 context in which to build the expressions. |
|
|
|
* @param solver The solver to use for the satisfiability evaluation. |
|
|
|
* @param subMdp The sub-MDP resulting from restricting the original MDP to the given command set. |
|
|
|
* @param originalMdp The original MDP. |
|
|
|
* @param phiStates A bit vector characterizing all phi states in the model. |
|
|
|
* @param psiState A bit vector characterizing all psi states in the model. |
|
|
|
* @param commandSet The currently chosen set of commands. |
|
|
|
* @param variableInformation A structure with information about the variables of the solver. |
|
|
|
*/ |
|
|
|
static void analyzeInsufficientProbabilitySolution(z3::context& context, z3::solver& solver, storm::models::Mdp<T> const& subMdp, storm::models::Mdp<T> const& originalMdp, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::set<uint_fast64_t> const& commandSet, VariableInformation& variableInformation, RelevancyInformation const& relevancyInformation) { |
|
|
|
// ruleOutSolution(context, solver, commandSet, variableInformation); |
|
|
|
|
|
|
|
storm::storage::BitVector reachableStates(subMdp.getNumberOfStates()); |
|
|
|
|
|
|
|
// Initialize the stack for the DFS. |
|
|
|
bool targetStateIsReachable = false; |
|
|
|
std::vector<uint_fast64_t> stack; |
|
|
|
stack.reserve(subMdp.getNumberOfStates()); |
|
|
|
for (auto initialState : subMdp.getInitialStates()) { |
|
|
|
stack.push_back(initialState); |
|
|
|
reachableStates.set(initialState, true); |
|
|
|
} |
|
|
|
|
|
|
|
storm::storage::SparseMatrix<T> const& transitionMatrix = subMdp.getTransitionMatrix(); |
|
|
|
std::vector<uint_fast64_t> const& nondeterministicChoiceIndices = subMdp.getNondeterministicChoiceIndices(); |
|
|
|
std::vector<std::set<uint_fast64_t>> const& subChoiceLabeling = subMdp.getChoiceLabeling(); |
|
|
|
|
|
|
|
std::set<uint_fast64_t> reachableLabels; |
|
|
|
|
|
|
|
while (!stack.empty()) { |
|
|
|
uint_fast64_t currentState = stack.back(); |
|
|
|
stack.pop_back(); |
|
|
|
|
|
|
|
for (uint_fast64_t currentChoice = nondeterministicChoiceIndices[currentState]; currentChoice < nondeterministicChoiceIndices[currentState + 1]; ++currentChoice) { |
|
|
|
bool choiceTargetsRelevantState = false; |
|
|
|
|
|
|
|
for (typename storm::storage::SparseMatrix<T>::ConstIndexIterator successorIt = transitionMatrix.constColumnIteratorBegin(currentChoice), successorIte = transitionMatrix.constColumnIteratorEnd(currentChoice); successorIt != successorIte; ++successorIt) { |
|
|
|
if (relevancyInformation.relevantStates.get(*successorIt) && currentState != *successorIt) { |
|
|
|
choiceTargetsRelevantState = true; |
|
|
|
if (!reachableStates.get(*successorIt)) { |
|
|
|
reachableStates.set(*successorIt, true); |
|
|
|
stack.push_back(*successorIt); |
|
|
|
} |
|
|
|
} else if (psiStates.get(*successorIt)) { |
|
|
|
targetStateIsReachable = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (choiceTargetsRelevantState) { |
|
|
|
for (auto label : subChoiceLabeling[currentChoice]) { |
|
|
|
reachableLabels.insert(label); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
LOG4CPLUS_DEBUG(logger, "Successfully determined reachable state space."); |
|
|
|
|
|
|
|
storm::storage::BitVector unreachableRelevantStates = ~reachableStates & relevancyInformation.relevantStates; |
|
|
|
storm::storage::BitVector statesThatCanReachTargetStates = storm::utility::graph::performProbGreater0E(subMdp, subMdp.getBackwardTransitions(), phiStates, psiStates); |
|
|
|
std::vector<std::set<uint_fast64_t>> guaranteedLabelSets = storm::utility::counterexamples::getGuaranteedLabelSets(originalMdp, statesThatCanReachTargetStates, relevancyInformation.relevantLabels); |
|
|
|
|
|
|
|
std::vector<std::set<uint_fast64_t>> const& choiceLabeling = originalMdp.getChoiceLabeling(); |
|
|
|
std::set<std::set<uint_fast64_t>> cutLabels; |
|
|
|
for (auto state : reachableStates) { |
|
|
|
for (auto currentChoice : relevancyInformation.relevantChoicesForRelevantStates.at(state)) { |
|
|
|
if (!storm::utility::set::isSubsetOf(choiceLabeling[currentChoice], commandSet)) { |
|
|
|
std::set<uint_fast64_t> currentLabelSet; |
|
|
|
for (auto label : choiceLabeling[currentChoice]) { |
|
|
|
if (commandSet.find(label) == commandSet.end()) { |
|
|
|
currentLabelSet.insert(label); |
|
|
|
} |
|
|
|
} |
|
|
|
std::set<uint_fast64_t> notTakenImpliedChoices; |
|
|
|
std::set_difference(guaranteedLabelSets[state].begin(), guaranteedLabelSets[state].end(), commandSet.begin(), commandSet.end(), std::inserter(notTakenImpliedChoices, notTakenImpliedChoices.begin())); |
|
|
|
currentLabelSet.insert(notTakenImpliedChoices.begin(), notTakenImpliedChoices.end()); |
|
|
|
|
|
|
|
cutLabels.insert(currentLabelSet); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<z3::expr> formulae; |
|
|
|
std::set<uint_fast64_t> unknownReachableLabels; |
|
|
|
std::set_difference(reachableLabels.begin(), reachableLabels.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownReachableLabels, unknownReachableLabels.begin())); |
|
|
|
for (auto label : unknownReachableLabels) { |
|
|
|
formulae.push_back(!variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); |
|
|
|
} |
|
|
|
for (auto const& cutLabelSet : cutLabels) { |
|
|
|
z3::expr cube = context.bool_val(true); |
|
|
|
for (auto cutLabel : cutLabelSet) { |
|
|
|
cube = cube && variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(cutLabel)); |
|
|
|
} |
|
|
|
|
|
|
|
formulae.push_back(cube); |
|
|
|
} |
|
|
|
|
|
|
|
LOG4CPLUS_DEBUG(logger, "Asserting reachability implications."); |
|
|
|
assertDisjunction(context, solver, formulae); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
public: |
|
|
@ -1196,12 +1312,13 @@ namespace storm { |
|
|
|
if (maximalReachabilityProbability == 0) { |
|
|
|
++zeroProbabilityCount; |
|
|
|
|
|
|
|
// If there was no target state reachable, analyze the solution and guide the solver into the |
|
|
|
// right direction. |
|
|
|
analyzeBadSolution(context, solver, subMdp, labeledMdp, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); |
|
|
|
// If there was no target state reachable, analyze the solution and guide the solver into the right direction. |
|
|
|
analyzeZeroProbabilitySolution(context, solver, subMdp, labeledMdp, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); |
|
|
|
} else { |
|
|
|
// In case we have not yet exceeded the given threshold, we have to rule out the current solution. |
|
|
|
ruleOutSolution(context, solver, commandSet, variableInformation); |
|
|
|
|
|
|
|
// If the reachability probability was greater than zero (i.e. there is a reachable target state), but the probability was insufficient to exceed |
|
|
|
// the given threshold, we analyze the solution and try to guide the solver into the right direction. |
|
|
|
analyzeInsufficientProbabilitySolution(context, solver, subMdp, labeledMdp, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); |
|
|
|
} |
|
|
|
} else { |
|
|
|
done = true; |
|
|
|