32 for (uint64_t currentState : initialStates) {
33 for (
auto const& successor : transitionMatrix.
getRowGroup(currentState)) {
35 result.
set(successor.getColumn());
44 bool useStepBound, uint_fast64_t maximalSteps, boost::optional<storm::storage::BitVector>
const& choiceFilter) {
50 std::vector<uint_fast64_t> stack;
51 stack.reserve(initialStates.
size());
52 for (uint64_t state : initialStates) {
53 if (constraintStates.
get(state)) {
54 stack.push_back(state);
59 std::vector<uint_fast64_t> stepStack;
60 std::vector<uint_fast64_t> remainingSteps;
62 stepStack.reserve(numberOfStates);
63 stepStack.insert(stepStack.begin(), stack.size(), maximalSteps);
64 remainingSteps.resize(numberOfStates);
65 for (
auto state : stack) {
66 remainingSteps[state] = maximalSteps;
71 uint_fast64_t currentState = 0, currentStepBound = 0;
72 while (!stack.empty()) {
73 currentState = stack.back();
77 currentStepBound = stepStack.back();
80 if (currentStepBound == 0) {
87 row = choiceFilter->getNextSetIndex(row);
90 while (row < rowGroupEnd) {
91 for (
auto const& successor : transitionMatrix.
getRow(row)) {
95 (!reachableStates.
get(successor.getColumn()) || (useStepBound && remainingSteps[successor.getColumn()] < currentStepBound - 1))) {
98 if (targetStates.
get(successor.getColumn())) {
99 reachableStates.
set(successor.getColumn());
100 }
else if (constraintStates.
get(successor.getColumn())) {
104 remainingSteps[successor.getColumn()] = currentStepBound - 1;
105 stepStack.push_back(currentStepBound - 1);
107 reachableStates.
set(successor.getColumn());
108 stack.push_back(successor.getColumn());
114 row = choiceFilter->getNextSetIndex(row);
119 return reachableStates;
129 for (
auto const& scc : decomposition) {
130 result.
set(*scc.begin());
141 unexploredStates = subsystem.
get();
142 acyclicStates = ~subsystem.
get();
147 std::vector<uint64_t> dfsStack;
149 dfsStack.push_back(start);
150 while (!dfsStack.empty()) {
151 uint64_t state = dfsStack.back();
152 if (unexploredStates.
get(state)) {
153 unexploredStates.
set(state,
false);
154 for (
auto const& entry : transitionMatrix.
getRowGroup(state)) {
156 if (unexploredStates.
get(entry.getColumn())) {
157 dfsStack.push_back(entry.getColumn());
159 if (!acyclicStates.
get(entry.getColumn())) {
167 acyclicStates.
set(state,
true);
186 uint_fast64_t state = 0;
187 for (uint64_t choice : choices) {
194 if (subsystem.
get(state)) {
195 bool choiceStaysInSubsys =
true;
196 for (
auto const& entry : transitionMatrix.
getRow(choice)) {
197 if (!subsystem.
get(entry.getColumn())) {
198 choiceStaysInSubsys =
false;
202 if (choiceStaysInSubsys) {
203 statesWithChoice.
set(state,
true);
219 statesWithChoice &= candidateStates;
221 for (uint64_t state : statesWithChoice) {
224 bool choiceStaysInCandidateSet =
true;
225 for (
auto const& entry : transitionMatrix.
getRow(choice)) {
226 if (!candidateStates.
get(entry.getColumn())) {
227 choiceStaysInCandidateSet =
false;
231 if (choiceStaysInCandidateSet) {
232 for (
auto const& entry : transitionMatrix.
getRow(choice)) {
233 choiceTargets.
set(entry.getColumn(),
true);
243 while (!candidateStates.
empty()) {
245 statesWithChoice &= candidateStates;
246 for (uint64_t state : statesWithChoice) {
247 bool stateHasChoice =
false;
250 bool choiceStaysInCandidateSet =
true;
251 for (
auto const& entry : transitionMatrix.
getRow(choice)) {
252 if (!candidateStates.
get(entry.getColumn())) {
253 choiceStaysInCandidateSet =
false;
257 if (choiceStaysInCandidateSet) {
258 stateHasChoice =
true;
262 if (!stateHasChoice) {
263 statesWithChoice.set(state,
false);
269 backwardTransitions, candidateStates, statesWithChoice);
272 if (newCandidates == candidateStates) {
276 candidateStates = std::move(newCandidates);
283 boost::optional<storm::storage::BitVector>
const& subsystem) {
286 std::vector<std::pair<storm::storage::sparse::state_type, uint_fast64_t>> stateQueue;
291 for (uint64_t initialState : initialStates) {
292 stateQueue.emplace_back(initialState, 0);
293 statesInQueue.
set(initialState);
297 while (currentPosition < stateQueue.size()) {
298 std::pair<storm::storage::sparse::state_type, std::size_t>
const& stateDistancePair = stateQueue[currentPosition];
299 distances[stateDistancePair.first] = stateDistancePair.second;
301 for (
auto const& successorEntry : transitionMatrix.
getRowGroup(stateDistancePair.first)) {
302 if (!statesInQueue.
get(successorEntry.getColumn())) {
303 if (!subsystem || subsystem.get()[successorEntry.getColumn()]) {
304 stateQueue.emplace_back(successorEntry.getColumn(), stateDistancePair.second + 1);
305 statesInQueue.
set(successorEntry.getColumn());
319 uint_fast64_t numberOfStates = phiStates.
size();
323 statesWithProbabilityGreater0 |= psiStates;
326 std::vector<uint_fast64_t> stack(psiStates.
begin(), psiStates.
end());
329 std::vector<uint_fast64_t> stepStack;
330 std::vector<uint_fast64_t> remainingSteps;
332 stepStack.reserve(numberOfStates);
334 remainingSteps.resize(numberOfStates);
335 for (uint64_t state : psiStates) {
336 remainingSteps[state] = maximalSteps;
341 uint_fast64_t currentState, currentStepBound;
342 while (!stack.empty()) {
343 currentState = stack.back();
347 currentStepBound = stepStack.back();
348 stepStack.pop_back();
349 if (currentStepBound == 0) {
355 entryIte = backwardTransitions.
end(currentState);
356 entryIt != entryIte; ++entryIt) {
357 if (phiStates[entryIt->getColumn()] &&
358 (!statesWithProbabilityGreater0.
get(entryIt->getColumn()) || (useStepBound && remainingSteps[entryIt->getColumn()] < currentStepBound - 1))) {
359 statesWithProbabilityGreater0.
set(entryIt->getColumn(),
true);
364 remainingSteps[entryIt->getColumn()] = currentStepBound - 1;
365 stepStack.push_back(currentStepBound - 1);
367 stack.push_back(entryIt->getColumn());
373 return statesWithProbabilityGreater0;
381 return statesWithProbability1;
390 return statesWithProbability1;
397 std::pair<storm::storage::BitVector, storm::storage::BitVector> result;
400 result.second =
performProb1(backwardTransitions, phiStates, psiStates, result.first);
401 result.first.complement();
409 std::pair<storm::storage::BitVector, storm::storage::BitVector> result;
411 result.second =
performProb1(backwardTransitions, phiStates, psiStates, result.first);
412 result.first.complement();
416template<storm::dd::DdType Type,
typename ValueType>
419 boost::optional<uint_fast64_t>
const& stepBound) {
425 uint_fast64_t iterations = 0;
426 while (lastIterationStates != statesWithProbabilityGreater0) {
427 if (stepBound && iterations >= stepBound.get()) {
431 lastIterationStates = statesWithProbabilityGreater0;
432 statesWithProbabilityGreater0 =
434 statesWithProbabilityGreater0 &= phiStates;
435 statesWithProbabilityGreater0 |= lastIterationStates;
439 return statesWithProbabilityGreater0;
442template<storm::dd::DdType Type,
typename ValueType>
449 return statesWithProbability1;
452template<storm::dd::DdType Type,
typename ValueType>
456 return performProb1(model, transitionMatrix, phiStates, psiStates, statesWithProbabilityGreater0);
459template<storm::dd::DdType Type,
typename ValueType>
471template<storm::dd::DdType Type,
typename ValueType>
483template<
typename T,
typename SchedulerValueType>
486 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices = transitionMatrix.
getRowGroupIndices();
488 for (uint64_t state : states) {
489 [[maybe_unused]]
bool setValue{
false};
491 if (rowFilter && !rowFilter->get(choice)) {
494 auto const row = transitionMatrix.
getRow(choice);
495 bool const allSuccessorsInStates = std::all_of(row.begin(), row.end(), [&states](
auto const& entry) { return states.get(entry.getColumn()); });
496 if (allSuccessorsInStates) {
498 scheduler.
setChoice(choice - nondeterministicChoiceIndices[state], state, memState);
504 STORM_LOG_ASSERT(setValue,
"Expected that at least one action for state " << state <<
" stays within the selected state");
508template<
typename T,
typename SchedulerValueType>
511 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices = transitionMatrix.
getRowGroupIndices();
513 for (uint64_t state : states) {
514 [[maybe_unused]]
bool setValue =
false;
515 for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) {
516 bool oneSuccessorInStates =
false;
517 for (
auto const& element : transitionMatrix.
getRow(choice)) {
518 if (states.
get(element.getColumn())) {
519 oneSuccessorInStates =
true;
523 if (oneSuccessorInStates) {
525 scheduler.
setChoice(choice - nondeterministicChoiceIndices[state], state, memState);
531 STORM_LOG_ASSERT(setValue,
"Expected that at least one action for state " << state <<
" leads with positive probability to the selected state");
535template<
typename T,
typename SchedulerValueType>
541 std::vector<uint_fast64_t> stack;
543 stack.insert(stack.end(), currentStates.
begin(), currentStates.
end());
544 uint_fast64_t currentState = 0;
546 while (!stack.empty()) {
547 currentState = stack.back();
551 predecessorEntryIte = backwardTransitions.
end(currentState);
552 predecessorEntryIt != predecessorEntryIte; ++predecessorEntryIt) {
553 uint_fast64_t
const& predecessor = predecessorEntryIt->getColumn();
554 if (phiStates.
get(predecessor) && !currentStates.
get(predecessor)) {
557 bool foundValidChoice =
false;
560 if (rowFilter && !rowFilter->get(row)) {
564 successorEntryIte = transitionMatrix.
end(row);
565 successorEntryIt != successorEntryIte; ++successorEntryIt) {
566 if (currentStates.
get(successorEntryIt->getColumn())) {
567 foundValidChoice =
true;
571 if (foundValidChoice) {
575 currentStates.
set(predecessor,
true);
576 stack.push_back(predecessor);
580 STORM_LOG_INFO_COND(foundValidChoice,
"Could not find a valid choice for ProbGreater0E state " << predecessor <<
".");
586template<
typename T,
typename SchedulerValueType>
592template<
typename T,
typename SchedulerValueType>
602 auto remainingStates = rewInfStates & ~trapStates;
603 if (!remainingStates.empty()) {
608template<
typename T,
typename SchedulerValueType>
612 boost::optional<storm::storage::BitVector>
const& rowFilter) {
614 for (uint64_t psiState : psiStates) {
616 if (!scheduler.
getChoice(psiState, memState).isDefined()) {
617 scheduler.
setChoice(0, psiState, memState);
623 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices = transitionMatrix.
getRowGroupIndices();
624 std::vector<uint_fast64_t> stack;
626 stack.insert(stack.end(), currentStates.
begin(), currentStates.
end());
627 uint_fast64_t currentState = 0;
629 while (!stack.empty()) {
630 currentState = stack.back();
634 predecessorEntryIte = backwardTransitions.
end(currentState);
635 predecessorEntryIt != predecessorEntryIte; ++predecessorEntryIt) {
636 if (phiStates.
get(predecessorEntryIt->getColumn()) && !currentStates.
get(predecessorEntryIt->getColumn())) {
639 for (uint_fast64_t row = nondeterministicChoiceIndices[predecessorEntryIt->getColumn()];
640 row < nondeterministicChoiceIndices[predecessorEntryIt->getColumn() + 1]; ++row) {
641 if (!rowFilter || rowFilter.get().get(row)) {
642 bool allSuccessorsInProb1EStates =
true;
643 bool hasSuccessorInCurrentStates =
false;
645 successorEntryIte = transitionMatrix.
end(row);
646 successorEntryIt != successorEntryIte; ++successorEntryIt) {
647 if (!prob1EStates.
get(successorEntryIt->getColumn())) {
648 allSuccessorsInProb1EStates =
false;
650 }
else if (currentStates.
get(successorEntryIt->getColumn())) {
651 hasSuccessorInCurrentStates =
true;
657 if (allSuccessorsInProb1EStates && hasSuccessorInCurrentStates) {
659 scheduler.
setChoice(row - nondeterministicChoiceIndices[predecessorEntryIt->getColumn()], predecessorEntryIt->getColumn(),
662 currentStates.
set(predecessorEntryIt->getColumn(),
true);
663 stack.push_back(predecessorEntryIt->getColumn());
676 size_t numberOfStates = phiStates.
size();
683 std::vector<uint_fast64_t> stack(psiStates.
begin(), psiStates.
end());
686 std::vector<uint_fast64_t> stepStack;
687 std::vector<uint_fast64_t> remainingSteps;
689 stepStack.reserve(numberOfStates);
691 remainingSteps.resize(numberOfStates);
692 for (uint64_t state : psiStates) {
693 remainingSteps[state] = maximalSteps;
698 uint_fast64_t currentState, currentStepBound;
699 while (!stack.empty()) {
700 currentState = stack.back();
704 currentStepBound = stepStack.back();
705 stepStack.pop_back();
706 if (currentStepBound == 0) {
712 entryIte = backwardTransitions.
end(currentState);
713 entryIt != entryIte; ++entryIt) {
714 if (phiStates.
get(entryIt->getColumn()) &&
715 (!statesWithProbabilityGreater0.
get(entryIt->getColumn()) || (useStepBound && remainingSteps[entryIt->getColumn()] < currentStepBound - 1))) {
719 remainingSteps[entryIt->getColumn()] = currentStepBound - 1;
720 stepStack.push_back(currentStepBound - 1);
722 statesWithProbabilityGreater0.
set(entryIt->getColumn(),
true);
723 stack.push_back(entryIt->getColumn());
728 return statesWithProbabilityGreater0;
736 return statesWithProbability0;
741 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
754 auto choicesOf = [&nondeterministicChoiceIndices](uint64_t
const state) {
755 return std::views::iota(nondeterministicChoiceIndices[state], nondeterministicChoiceIndices[state + 1]);
759 auto choiceStaysInCandidates = [&](uint64_t
const choice) ->
bool {
760 return (!choiceConstraint || choiceConstraint->get(choice)) &&
761 std::ranges::all_of(transitionMatrix.
getRow(choice), [&candidates](
auto const& entry) { return candidates.get(entry.getColumn()); });
765 auto satisfiesSafety = [&](uint64_t
const state) ->
bool {
return psiStates.
get(state) || std::ranges::any_of(choicesOf(state), choiceStaysInCandidates); };
767 std::vector<uint64_t> stack;
770 auto propagateRemovals = [&] {
771 while (!stack.empty()) {
772 uint64_t
const removedState = stack.back();
774 for (
auto const& predecessorEntry : backwardTransitions.
getRow(removedState)) {
775 uint64_t
const predecessor = predecessorEntry.getColumn();
776 if (candidates.
get(predecessor) && !satisfiesSafety(predecessor)) {
777 candidates.
set(predecessor,
false);
778 stack.push_back(predecessor);
787 auto isSafeChoiceReachingAux = [&](uint64_t
const choice) ->
bool {
788 if (choiceConstraint && !choiceConstraint->get(choice)) {
791 bool hasReachingSuccessor =
false;
792 for (
auto const& successorEntry : transitionMatrix.
getRow(choice)) {
793 if (!candidates.
get(successorEntry.getColumn())) {
796 hasReachingSuccessor = hasReachingSuccessor || auxStates.
get(successorEntry.getColumn());
798 return hasReachingSuccessor;
802 auto gatherReachingStates = [&] {
803 auxStates = psiStates;
804 stack.assign(psiStates.
begin(), psiStates.
end());
805 while (!stack.empty()) {
806 uint64_t
const currentState = stack.back();
808 for (
auto const& predecessorEntry : backwardTransitions.
getRow(currentState)) {
809 uint64_t
const predecessor = predecessorEntry.getColumn();
810 if (candidates.
get(predecessor) && !auxStates.
get(predecessor) && std::ranges::any_of(choicesOf(predecessor), isSafeChoiceReachingAux)) {
811 auxStates.
set(predecessor,
true);
812 stack.push_back(predecessor);
819 for (uint64_t
const state : candidates) {
820 if (!satisfiesSafety(state)) {
821 candidates.
set(state,
false);
822 stack.push_back(state);
830 STORM_LOG_ASSERT(stack.empty(),
"Expected empty stack after propagating removals.");
832 gatherReachingStates();
833 STORM_LOG_ASSERT(stack.empty(),
"Expected empty stack after gathering reaching states.");
835 auxStates ^= candidates;
837 for (uint64_t
const state : auxStates) {
838 candidates.
set(state,
false);
839 stack.push_back(state);
842 }
while (!stack.empty());
847template<
typename T,
typename RM>
856 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
860 std::pair<storm::storage::BitVector, storm::storage::BitVector> result;
865 result.second =
performProb1E(transitionMatrix, nondeterministicChoiceIndices, backwardTransitions, result.first, psiStates);
867 result.first.complement();
872template<
typename T,
typename RM>
882 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
885 boost::optional<storm::storage::BitVector>
const& choiceConstraint) {
886 size_t numberOfStates = phiStates.
size();
893 std::vector<uint_fast64_t> stack(psiStates.
begin(), psiStates.
end());
896 std::vector<uint_fast64_t> stepStack;
897 std::vector<uint_fast64_t> remainingSteps;
899 stepStack.reserve(numberOfStates);
901 remainingSteps.resize(numberOfStates);
902 for (uint64_t state : psiStates) {
903 remainingSteps[state] = maximalSteps;
908 uint_fast64_t currentState, currentStepBound;
909 while (!stack.empty()) {
910 currentState = stack.back();
914 currentStepBound = stepStack.back();
915 stepStack.pop_back();
916 if (currentStepBound == 0) {
922 predecessorEntryIte = backwardTransitions.
end(currentState);
923 predecessorEntryIt != predecessorEntryIte; ++predecessorEntryIt) {
924 if (phiStates.
get(predecessorEntryIt->getColumn())) {
925 if (!statesWithProbabilityGreater0.
get(predecessorEntryIt->getColumn())) {
931 uint_fast64_t row = nondeterministicChoiceIndices[predecessorEntryIt->getColumn()];
932 uint_fast64_t
const& endOfGroup = nondeterministicChoiceIndices[predecessorEntryIt->getColumn() + 1];
933 if (!choiceConstraint || choiceConstraint->getNextSetIndex(row) < endOfGroup) {
934 bool addToStatesWithProbabilityGreater0 =
true;
935 for (; row < endOfGroup; ++row) {
936 if (!choiceConstraint || choiceConstraint->get(row)) {
937 bool hasAtLeastOneSuccessorWithProbabilityGreater0 =
false;
939 successorEntryIte = transitionMatrix.
end(row);
940 successorEntryIt != successorEntryIte; ++successorEntryIt) {
941 if (statesWithProbabilityGreater0.
get(successorEntryIt->getColumn())) {
942 hasAtLeastOneSuccessorWithProbabilityGreater0 =
true;
947 if (!hasAtLeastOneSuccessorWithProbabilityGreater0) {
948 addToStatesWithProbabilityGreater0 =
false;
955 if (addToStatesWithProbabilityGreater0) {
959 remainingSteps[predecessorEntryIt->getColumn()] = currentStepBound - 1;
960 stepStack.push_back(currentStepBound - 1);
962 statesWithProbabilityGreater0.
set(predecessorEntryIt->getColumn(),
true);
963 stack.push_back(predecessorEntryIt->getColumn());
967 }
else if (useStepBound && remainingSteps[predecessorEntryIt->getColumn()] < currentStepBound - 1) {
970 bool predecessorIsValid =
true;
971 if (choiceConstraint) {
972 predecessorIsValid =
false;
973 uint_fast64_t row = choiceConstraint->getNextSetIndex(nondeterministicChoiceIndices[predecessorEntryIt->getColumn()]);
974 uint_fast64_t
const& endOfGroup = nondeterministicChoiceIndices[predecessorEntryIt->getColumn() + 1];
975 for (; row < endOfGroup && !predecessorIsValid; row = choiceConstraint->getNextSetIndex(row + 1)) {
976 for (
auto const& entry : transitionMatrix.
getRow(row)) {
977 if (entry.getColumn() == currentState) {
978 predecessorIsValid =
true;
984 if (predecessorIsValid) {
985 remainingSteps[predecessorEntryIt->getColumn()] = currentStepBound - 1;
986 stepStack.push_back(currentStepBound - 1);
987 stack.push_back(predecessorEntryIt->getColumn());
994 return statesWithProbabilityGreater0;
997template<
typename T,
typename RM>
1004 return statesWithProbability0;
1009 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
1013 performProbGreater0A(transitionMatrix, nondeterministicChoiceIndices, backwardTransitions, phiStates, psiStates);
1015 return statesWithProbability0;
1018template<
typename T,
typename RM>
1027 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
1030 size_t numberOfStates = phiStates.
size();
1034 std::vector<uint_fast64_t> stack;
1035 stack.reserve(numberOfStates);
1039 uint_fast64_t currentState;
1043 stack.insert(stack.end(), psiStates.
begin(), psiStates.
end());
1045 while (!stack.empty()) {
1046 currentState = stack.back();
1050 predecessorEntryIte = backwardTransitions.
end(currentState);
1051 predecessorEntryIt != predecessorEntryIte; ++predecessorEntryIt) {
1052 if (phiStates.
get(predecessorEntryIt->getColumn()) && !nextStates.
get(predecessorEntryIt->getColumn())) {
1056 bool addToStatesWithProbability1 =
true;
1057 for (uint_fast64_t row = nondeterministicChoiceIndices[predecessorEntryIt->getColumn()];
1058 row < nondeterministicChoiceIndices[predecessorEntryIt->getColumn() + 1]; ++row) {
1059 bool hasAtLeastOneSuccessorWithProbability1 =
false;
1061 successorEntryIte = transitionMatrix.
end(row);
1062 successorEntryIt != successorEntryIte; ++successorEntryIt) {
1063 if (!currentStates.
get(successorEntryIt->getColumn())) {
1064 addToStatesWithProbability1 =
false;
1065 goto afterCheckLoop;
1067 if (nextStates.
get(successorEntryIt->getColumn())) {
1068 hasAtLeastOneSuccessorWithProbability1 =
true;
1072 if (!hasAtLeastOneSuccessorWithProbability1) {
1073 addToStatesWithProbability1 =
false;
1082 if (addToStatesWithProbability1) {
1083 nextStates.
set(predecessorEntryIt->getColumn(),
true);
1084 stack.push_back(predecessorEntryIt->getColumn());
1091 if (currentStates == nextStates) {
1094 currentStates = std::move(nextStates);
1097 return currentStates;
1102 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
1106 std::pair<storm::storage::BitVector, storm::storage::BitVector> result;
1107 result.first =
performProb0E(transitionMatrix, nondeterministicChoiceIndices, backwardTransitions, phiStates, psiStates);
1111 result.second =
performProb0A(backwardTransitions, ~psiStates, result.first);
1115template<
typename T,
typename RM>
1123template<storm::dd::DdType Type,
typename ValueType>
1133 while (!frontier.
isZero()) {
1137 scheduler = scheduler || (frontier && statesAndChoicesWithProbabilityGreater0E).existsAbstractRepresentative(model.
getNondeterminismVariables());
1138 statesWithProbabilityGreater0E |= frontier;
1144template<storm::dd::DdType Type,
typename ValueType>
1154 while (lastIterationStates != statesWithProbabilityGreater0E) {
1155 lastIterationStates = statesWithProbabilityGreater0E;
1156 statesWithProbabilityGreater0E =
1158 statesWithProbabilityGreater0E &= phiStates;
1159 statesWithProbabilityGreater0E |= lastIterationStates;
1162 return statesWithProbabilityGreater0E;
1165template<storm::dd::DdType Type,
typename ValueType>
1171template<storm::dd::DdType Type,
typename ValueType>
1180 while (lastIterationStates != statesWithProbabilityGreater0A) {
1181 lastIterationStates = statesWithProbabilityGreater0A;
1182 statesWithProbabilityGreater0A =
1186 statesWithProbabilityGreater0A &= phiStates;
1187 statesWithProbabilityGreater0A |= psiStates;
1190 return statesWithProbabilityGreater0A;
1193template<storm::dd::DdType Type,
typename ValueType>
1199template<storm::dd::DdType Type,
typename ValueType>
1207 while (lastIterationStates != statesWithProbability1A) {
1208 lastIterationStates = statesWithProbability1A;
1210 statesWithProbability1A = transitionMatrix.
implies(statesWithProbability1A).universalAbstract(model.
getColumnVariables());
1213 statesWithProbability1A &= statesWithProbabilityGreater0A;
1214 statesWithProbability1A |= psiStates;
1217 return statesWithProbability1A;
1220template<storm::dd::DdType Type,
typename ValueType>
1228 bool outerLoopDone =
false;
1229 while (!outerLoopDone) {
1232 bool innerLoopDone =
false;
1233 while (!innerLoopDone) {
1241 temporary &= phiStates;
1242 temporary |= psiStates;
1244 if (innerStates == temporary) {
1245 innerLoopDone =
true;
1247 innerStates = temporary;
1251 if (statesWithProbability1E == innerStates) {
1252 outerLoopDone =
true;
1254 statesWithProbability1E = innerStates;
1258 return statesWithProbability1E;
1261template<storm::dd::DdType Type,
typename ValueType>
1271 bool innerLoopDone =
false;
1272 while (!innerLoopDone) {
1278 temporary &= temporary2;
1279 temporary &= phiStates;
1285 temporary |= psiStates;
1287 if (innerStates == temporary) {
1288 innerLoopDone =
true;
1290 innerStates = temporary;
1297template<storm::dd::DdType Type,
typename ValueType>
1303template<storm::dd::DdType Type,
typename ValueType>
1308 result.first =
performProb0A(model, transitionMatrix, phiStates, psiStates);
1313template<storm::dd::DdType Type,
typename ValueType>
1319template<storm::dd::DdType Type,
typename ValueType>
1324 result.first =
performProb0E(model, transitionMatrix, phiStates, psiStates);
1329template<
typename ValueType>
1338 std::vector<uint_fast64_t> stack(psiStates.
begin(), psiStates.
end());
1341 uint_fast64_t currentState;
1342 while (!stack.empty()) {
1343 currentState = stack.back();
1347 for (
auto const& player2PredecessorEntry : player1BackwardTransitions.
getRow(currentState)) {
1348 uint64_t player2Predecessor = player2PredecessorEntry.getColumn();
1350 bool addPlayer2State =
false;
1351 if (player2Direction == OptimizationDirection::Minimize) {
1352 bool allChoicesHavePlayer1State =
true;
1355 bool choiceHasPlayer1State =
false;
1356 for (
auto const& entry : transitionMatrix.
getRow(row)) {
1358 choiceHasPlayer1State =
true;
1362 if (!choiceHasPlayer1State) {
1363 allChoicesHavePlayer1State =
false;
1366 if (allChoicesHavePlayer1State) {
1367 addPlayer2State =
true;
1370 addPlayer2State =
true;
1373 if (addPlayer2State) {
1378 uint64_t player1Predecessor = player2BackwardTransitions[player2Predecessor];
1381 bool addPlayer1State =
false;
1382 if (player1Direction == OptimizationDirection::Minimize) {
1383 bool allPlayer2Successors =
true;
1384 for (uint64_t player2State = player1Groups[player1Predecessor]; player2State < player1Groups[player1Predecessor + 1];
1387 allPlayer2Successors =
false;
1391 if (allPlayer2Successors) {
1392 addPlayer1State =
true;
1395 addPlayer1State =
true;
1398 if (addPlayer1State) {
1400 stack.emplace_back(player1Predecessor);
1415 if (player1Direction == storm::OptimizationDirection::Minimize) {
1417 [[maybe_unused]]
bool foundProb0Successor =
false;
1418 uint64_t player2State;
1419 for (player2State = player1Groups[player1State]; player2State < player1Groups[player1State + 1]; ++player2State) {
1421 foundProb0Successor =
true;
1425 STORM_LOG_ASSERT(foundProb0Successor,
"Expected at least one state 2 successor with probability 0.");
1437 if (player2Direction == storm::OptimizationDirection::Minimize) {
1439 [[maybe_unused]]
bool foundProb0SuccessorDistribution =
false;
1443 bool distributionHasOnlyProb0Successors =
true;
1444 for (
auto const& player1SuccessorEntry : transitionMatrix.
getRow(row)) {
1446 distributionHasOnlyProb0Successors =
false;
1450 if (distributionHasOnlyProb0Successors) {
1451 foundProb0SuccessorDistribution =
true;
1456 STORM_LOG_ASSERT(foundProb0SuccessorDistribution,
"Expected at least one distribution with only successors with probability 0.");
1468template<storm::dd::DdType Type,
typename ValueType>
1482 if (player2Strategy == OptimizationDirection::Minimize) {
1487 player2States |= tmp;
1489 if (player1Strategy == OptimizationDirection::Minimize) {
1496 tmp |= player1States;
1498 if (tmp == player1States) {
1502 player1States = tmp;
1508 std::set<storm::expressions::Variable> variablesToAbstract(model.
getColumnVariables());
1510 player2States = !player2States && transitionMatrix.
existsAbstract(variablesToAbstract);
1519 boost::optional<storm::dd::Bdd<Type>> player2StrategyBdd;
1520 if (producePlayer2Strategy) {
1525 boost::optional<storm::dd::Bdd<Type>> player1StrategyBdd;
1526 if (producePlayer1Strategy) {
1528 onlyProb0Successors = (player1States && onlyProb0Successors).existsAbstract(model.
getPlayer2Variables());
1537template<
typename ValueType>
1543 boost::optional<storm::storage::BitVector>
const& player1Candidates) {
1546 if (player1Candidates) {
1553 bool produceStrategiesInIteration =
false;
1556 std::vector<uint_fast64_t> stack;
1557 bool maybeStatesDone =
false;
1558 while (!maybeStatesDone || produceStrategiesInIteration) {
1563 stack.insert(stack.end(), psiStates.
begin(), psiStates.
end());
1566 uint_fast64_t currentState;
1567 while (!stack.empty()) {
1568 currentState = stack.back();
1571 for (
auto player2PredecessorEntry : player1BackwardTransitions.
getRow(currentState)) {
1572 uint64_t player2Predecessor = player2PredecessorEntry.getColumn();
1573 if (!player2Solution.
get(player2PredecessorEntry.getColumn())) {
1574 bool addPlayer2State = player2Direction == storm::OptimizationDirection::Minimize;
1577 for (uint64_t row = validChoice; row < transitionMatrix.
getRowGroupIndices()[player2Predecessor + 1]; ++row) {
1578 bool choiceHasSolutionSuccessor =
false;
1579 bool choiceStaysInMaybeStates =
true;
1580 for (
auto const& entry : transitionMatrix.
getRow(row)) {
1581 if (player1Solution.
get(entry.getColumn())) {
1582 choiceHasSolutionSuccessor =
true;
1585 choiceStaysInMaybeStates =
false;
1590 if (choiceHasSolutionSuccessor && choiceStaysInMaybeStates) {
1591 if (player2Direction == storm::OptimizationDirection::Maximize) {
1593 addPlayer2State =
true;
1596 }
else if (player2Direction == storm::OptimizationDirection::Minimize) {
1597 addPlayer2State =
false;
1602 if (addPlayer2State) {
1603 player2Solution.
set(player2Predecessor);
1604 if (produceStrategiesInIteration) {
1610 uint64_t player1Predecessor = player2BackwardTransitions[player2Predecessor];
1612 if (!player1Solution.
get(player1Predecessor)) {
1613 bool addPlayer1State = player1Direction == storm::OptimizationDirection::Minimize;
1615 validChoice = player1Groups[player1Predecessor];
1616 for (uint64_t player2Successor = validChoice; player2Successor < player1Groups[player1Predecessor + 1]; ++player2Successor) {
1617 if (player2Solution.
get(player2Successor)) {
1618 if (player1Direction == storm::OptimizationDirection::Maximize) {
1619 validChoice = player2Successor;
1620 addPlayer1State =
true;
1623 }
else if (player1Direction == storm::OptimizationDirection::Minimize) {
1624 addPlayer1State =
false;
1629 if (addPlayer1State) {
1630 player1Solution.
set(player1Predecessor);
1632 if (produceStrategiesInIteration) {
1636 stack.emplace_back(player1Predecessor);
1645 maybeStatesDone =
true;
1650 produceStrategiesInIteration = !produceStrategiesInIteration && strategyPair;
1660template<storm::dd::DdType Type,
typename ValueType>
1668 if (player1Candidates) {
1669 maybePlayer1States &= player1Candidates.get();
1676 bool produceStrategiesInIteration =
false;
1677 boost::optional<storm::dd::Bdd<Type>> player1StrategyBdd;
1678 boost::optional<storm::dd::Bdd<Type>> consideredPlayer1States;
1679 boost::optional<storm::dd::Bdd<Type>> player2StrategyBdd;
1680 boost::optional<storm::dd::Bdd<Type>> consideredPlayer2States;
1682 bool maybeStatesDone =
false;
1683 while (!maybeStatesDone || produceStrategiesInIteration) {
1684 bool solutionStatesDone =
false;
1687 if (produceStrategiesInIteration) {
1688 if (player1Strategy == storm::OptimizationDirection::Maximize) {
1689 player1StrategyBdd = model.
getManager().getBddZero();
1690 consideredPlayer1States = model.
getManager().getBddZero();
1692 if (player2Strategy == storm::OptimizationDirection::Maximize) {
1693 player2StrategyBdd = model.
getManager().getBddZero();
1694 consideredPlayer2States = model.
getManager().getBddZero();
1700 while (!solutionStatesDone) {
1713 storm::dd::Bdd<Type> valid = phiStates && distributionsStayingInMaybe && distributionsWithProb1Successor;
1717 if (player2Strategy == OptimizationDirection::Minimize) {
1720 if (produceStrategiesInIteration) {
1727 if (produceStrategiesInIteration) {
1728 consideredPlayer2States.get() |= valid;
1732 player2Solution |= valid;
1735 if (player1Strategy == OptimizationDirection::Minimize) {
1738 if (produceStrategiesInIteration) {
1745 if (produceStrategiesInIteration) {
1746 consideredPlayer1States.get() |= valid;
1756 if (valid == player1Solution) {
1757 solutionStatesDone =
true;
1759 player1Solution = valid;
1765 if (player1Solution == maybePlayer1States) {
1766 maybePlayer2States = player2Solution;
1767 maybeStatesDone =
true;
1771 produceStrategiesInIteration = !produceStrategiesInIteration && ((producePlayer1Strategy && player1Strategy == OptimizationDirection::Maximize) ||
1772 (producePlayer2Strategy && player2Strategy == OptimizationDirection::Maximize));
1776 maybePlayer1States = player1Solution;
1784 bool strategiesToCompute = (producePlayer1Strategy && !player1StrategyBdd) || (producePlayer2Strategy && !player2StrategyBdd);
1785 if (strategiesToCompute) {
1787 if (producePlayer2Strategy && !player2StrategyBdd) {
1790 if (producePlayer1Strategy && !player1StrategyBdd) {
1791 relevantStates = (maybePlayer1States && relevantStates).existsAbstract(model.
getPlayer2Variables());
1801 std::vector<uint_fast64_t>& recursionStack,
1804 if (!visitedStates.
get(state)) {
1805 recursionStack.push_back(state);
1806 iteratorRecursionStack.push_back(matrix.
begin(state));
1808 recursionStepForward:
1809 while (!recursionStack.empty()) {
1810 uint_fast64_t currentState = recursionStack.back();
1813 visitedStates.
set(currentState,
true);
1815 recursionStepBackward:
1816 for (; successorIterator != matrix.
end(currentState); ++successorIterator) {
1817 if (!visitedStates.
get(successorIterator->getColumn())) {
1819 recursionStack.push_back(successorIterator->getColumn());
1822 iteratorRecursionStack.push_back(matrix.
begin(successorIterator->getColumn()));
1824 goto recursionStepForward;
1828 topologicalSort.push_back(currentState);
1832 recursionStack.pop_back();
1833 iteratorRecursionStack.pop_back();
1838 if (recursionStack.size() > 0) {
1839 currentState = recursionStack.back();
1840 successorIterator = iteratorRecursionStack.back();
1842 goto recursionStepBackward;
1852 std::vector<uint_fast64_t> stateQueue;
1854 std::vector<uint_fast64_t> result;
1859 for (
auto const& state : firstStates) {
1860 stateQueue.push_back(state);
1861 result[count] = state;
1866 while (!stateQueue.empty()) {
1867 auto state = stateQueue.back();
1868 stateQueue.pop_back();
1869 seenStates.
set(state);
1870 for (
auto const& successorEntry : matrix.
getRowGroup(state)) {
1871 auto succ = successorEntry.geColumn();
1872 if (!seenStates[succ]) {
1873 result[count] = succ;
1875 stateQueue.insert(stateQueue.begin(), succ);
1886 uint_fast64_t numberOfStates = matrix.
getRowCount();
1889 std::vector<uint_fast64_t> topologicalSort;
1890 topologicalSort.reserve(numberOfStates);
1893 std::vector<uint_fast64_t> recursionStack;
1895 std::vector<typename storm::storage::SparseMatrix<T>::const_iterator> iteratorRecursionStack;
1896 iteratorRecursionStack.reserve(numberOfStates);
1900 for (
auto const state : firstStates) {
1903 for (uint_fast64_t state = 0; state < numberOfStates; ++state) {
1907 return topologicalSort;
1913 boost::optional<storm::storage::BitVector>
const& choiceFilter);
1924 boost::optional<storm::storage::BitVector>
const& subsystem);
1928 bool useStepBound =
false, uint_fast64_t maximalSteps = 0);
1947 boost::optional<storm::storage::BitVector>
const& rowFilter);
1958 boost::optional<storm::storage::BitVector>
const& rowFilter = boost::none);
1962 bool useStepBound =
false, uint_fast64_t maximalSteps = 0);
1968 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
1971 boost::optional<storm::storage::BitVector>
const& choiceConstraint = boost::none);
1978 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
1988 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
1991 bool useStepBound =
false, uint_fast64_t maximalSteps = 0,
1992 boost::optional<storm::storage::BitVector>
const& choiceConstraint = boost::none);
2005 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2024 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2029 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2052 boost::optional<storm::storage::BitVector>
const& player1Candidates);
2060 boost::optional<storm::storage::BitVector>
const& choiceFilter);
2065 boost::optional<storm::storage::BitVector>
const& subsystem);
2076 bool useStepBound =
false, uint_fast64_t maximalSteps = 0);
2085template std::pair<storm::storage::BitVector, storm::storage::BitVector>
performProb01(
2089template std::pair<storm::storage::BitVector, storm::storage::BitVector>
performProb01(
2097 boost::optional<storm::storage::BitVector>
const& rowFilter);
2109 boost::optional<storm::storage::BitVector>
const& rowFilter = boost::none);
2113 bool useStepBound =
false, uint_fast64_t maximalSteps = 0);
2119 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2122 boost::optional<storm::storage::BitVector>
const& choiceConstraint = boost::none);
2138 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2141 bool useStepBound =
false, uint_fast64_t maximalSteps = 0,
2142 boost::optional<storm::storage::BitVector>
const& choiceConstraint = boost::none);
2149 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2154 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2168 std::vector<uint64_t>
const& player1RowGrouping,
2175 std::vector<uint64_t>
const& player1RowGrouping,
2180 boost::optional<storm::storage::BitVector>
const& player1Candidates);
2183 std::vector<uint64_t>
const& firstStates);
2193 boost::optional<storm::storage::BitVector>
const& choiceFilter);
2208 bool useStepBound =
false, uint_fast64_t maximalSteps = 0);
2239 boost::optional<storm::storage::BitVector>
const& rowFilter = boost::none);
2243 bool useStepBound =
false, uint_fast64_t maximalSteps = 0);
2249 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2252 boost::optional<storm::storage::BitVector>
const& choiceConstraint = boost::none);
2268 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2271 bool useStepBound =
false, uint_fast64_t maximalSteps = 0,
2272 boost::optional<storm::storage::BitVector>
const& choiceConstraint = boost::none);
2279 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2284 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2298 std::vector<uint64_t>
const& player1RowGrouping,
2305 std::vector<uint64_t>
const& player1RowGrouping,
2310 boost::optional<storm::storage::BitVector>
const& player1Candidates);
2322 boost::optional<storm::storage::BitVector>
const& choiceFilter);
2327 boost::optional<storm::storage::BitVector>
const& subsystem);
2338 bool useStepBound =
false, uint_fast64_t maximalSteps = 0);
2347template std::pair<storm::storage::BitVector, storm::storage::BitVector>
performProb01(
2351template std::pair<storm::storage::BitVector, storm::storage::BitVector>
performProb01(
2359 boost::optional<storm::storage::BitVector>
const& rowFilter);
2375 boost::optional<storm::storage::BitVector>
const& rowFilter = boost::none);
2379 bool useStepBound =
false, uint_fast64_t maximalSteps = 0);
2385 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2388 boost::optional<storm::storage::BitVector>
const& choiceConstraint = boost::none);
2404 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2407 bool useStepBound =
false, uint_fast64_t maximalSteps = 0,
2408 boost::optional<storm::storage::BitVector>
const& choiceConstraint = boost::none);
2415 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2420 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2434 std::vector<uint64_t>
const& player1RowGrouping,
2441 std::vector<uint64_t>
const& player1RowGrouping,
2446 boost::optional<storm::storage::BitVector>
const& player1Candidates);
2449 std::vector<uint64_t>
const& firstStates);
2455 boost::optional<storm::storage::BitVector>
const& choiceFilter);
2460 boost::optional<storm::storage::BitVector>
const& subsystem);
2471 bool useStepBound =
false, uint_fast64_t maximalSteps = 0);
2480template std::pair<storm::storage::BitVector, storm::storage::BitVector>
performProb01(
2484template std::pair<storm::storage::BitVector, storm::storage::BitVector>
performProb01(
2493 boost::optional<storm::storage::BitVector>
const& rowFilter = boost::none);
2497 bool useStepBound =
false, uint_fast64_t maximalSteps = 0);
2503 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2506 boost::optional<storm::storage::BitVector>
const& choiceConstraint = boost::none);
2522 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2525 bool useStepBound =
false, uint_fast64_t maximalSteps = 0,
2526 boost::optional<storm::storage::BitVector>
const& choiceConstraint = boost::none);
2532 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2540 std::vector<uint_fast64_t>
const& nondeterministicChoiceIndices,
2554 std::vector<uint64_t>
const& firstStates);
2562 boost::optional<uint_fast64_t>
const& stepBound = boost::optional<uint_fast64_t>());
2661 boost::optional<uint_fast64_t>
const& stepBound = boost::optional<uint_fast64_t>());
2745 bool producePlayer2Strategy);