36template<
typename ValueType>
37std::optional<typename storm::transformer::EndComponentEliminator<ValueType>::EndComponentEliminatorReturnType>
eliminateEndComponents(
38 storm::storage::BitVector const& possibleEcStates,
bool addRowAtRepresentativeState, std::optional<uint64_t>
const representativeRowEntry,
48 matrix, ecs, allRowGroups, addRowAtRepresentativeState ? allRowGroups : ~allRowGroups, representativeRowEntry.has_value());
51 matrix = std::move(ecElimResult.matrix);
52 if (addRowAtRepresentativeState && representativeRowEntry) {
53 auto const columnIndex = ecElimResult.oldToNewStateMapping[*representativeRowEntry];
54 for (
auto representativeRowIndex : ecElimResult.sinkRows) {
55 auto row = matrix.
getRow(representativeRowIndex);
56 STORM_LOG_ASSERT(row.getNumberOfEntries() == 1,
"Unexpected number of entries in representative row.");
57 auto& entry = *row.begin();
58 entry.setColumn(columnIndex);
63 auto updateRowValue = [&ecElimResult](std::vector<ValueType>& rowValues) {
64 std::vector<ValueType> newRowValues;
65 newRowValues.reserve(ecElimResult.newToOldRowMapping.size());
66 for (
auto oldRowIndex : ecElimResult.newToOldRowMapping) {
67 newRowValues.push_back(rowValues[oldRowIndex]);
69 rowValues = std::move(newRowValues);
71 std::all_of(ecElimResult.sinkRows.begin(), ecElimResult.sinkRows.end(), [&rowValues](
auto i) { return storm::utility::isZero(rowValues[i]); }),
72 "Sink rows are expected to have zero value");
74 updateRowValue(rowValues1);
76 updateRowValue(*rowValues2);
80 storm::storage::BitVector newRowsWithSum1(ecElimResult.newToOldRowMapping.size(),
true);
81 uint64_t newRowIndex = 0;
82 for (
auto oldRowIndex : ecElimResult.newToOldRowMapping) {
83 if ((addRowAtRepresentativeState && !representativeRowEntry.has_value() && ecElimResult.sinkRows.get(newRowIndex)) || !rowsWithSum1.
get(oldRowIndex)) {
84 newRowsWithSum1.set(newRowIndex,
false);
88 rowsWithSum1 = std::move(newRowsWithSum1);
93template<
typename ValueType,
typename SolutionType = ValueType>
97 std::optional<std::vector<uint64_t>>& schedulerOutput) {
104 relevantValues.
set(initialState,
true);
109 return {goal.
direction(), relevantValues};
116 solver->setRequirementsChecked();
117 solver->setHasUniqueSolution(
true);
118 solver->setHasNoEndComponents(
true);
121 solver->setTrackScheduler(schedulerOutput.has_value());
124 solver->solveEquations(env, x, rowValues);
126 if (schedulerOutput) {
127 *schedulerOutput = std::move(
solver->getSchedulerChoices());
130 return x[initialState];
137template<
typename ValueType>
142 std::unique_ptr<storm::storage::Scheduler<ValueType>> scheduler;
143 if (computeScheduler) {
144 scheduler = std::make_unique<storm::storage::Scheduler<ValueType>>(transitionMatrix.
getRowGroupCount());
147 auto reachabilityEnv = env;
151 if (initialStates.
empty()) {
155 auto const subTargets = targetStates % reachableStates;
157 if (subTargets.empty()) {
160 auto const subInits = initialStates % reachableStates;
161 auto const submatrix = transitionMatrix.
getSubmatrix(
true, reachableStates, reachableStates);
166 auto origInitIt = initialStates.
begin();
167 for (
auto subInit : subInits) {
168 auto const& val = subResult.values[subInit];
170 nonZeroResults.emplace(*origInitIt, val);
175 if (computeScheduler) {
176 auto submatrixIdx = 0;
177 for (
auto state : reachableStates) {
178 scheduler->setChoice(subResult.scheduler->getChoice(submatrixIdx), state);
186template<
typename ValueType>
205 std::unique_ptr<storm::storage::Scheduler<ValueType>>
207 std::unique_ptr<storm::storage::Scheduler<ValueType>>
224template<
typename ValueType>
230 auto extendedConditionStates =
233 std::map<uint64_t, ValueType> nonZeroTargetStateValues;
234 auto const extendedTargetStates =
236 auto const targetAndNotCondFailStates = extendedTargetStates & ~(extendedConditionStates | universalObservationFailureStates);
240 env, nonZeroTargetStateValues, dir, transitionMatrix, extendedConditionStates, allStates, extendedTargetStates, computeScheduler);
242 env, nonZeroTargetStateValues, dir, transitionMatrix, targetAndNotCondFailStates, allStates, extendedConditionStates, computeScheduler);
245 auto terminalStatesThatReachCondition = extendedConditionStates;
246 for (
auto state : targetAndNotCondFailStates) {
247 if (nonZeroTargetStateValues.contains(state)) {
248 terminalStatesThatReachCondition.set(state,
true);
253 auto terminalStates = extendedConditionStates | extendedTargetStates | universalObservationFailureStates;
262 auto nonTerminalStates = ~terminalStates;
265 backwardTransitions, nonTerminalStates, terminalStatesThatReachCondition);
271 .terminalStates = std::move(terminalStates),
272 .conditionStates = std::move(extendedConditionStates),
273 .targetStates = std::move(extendedTargetStates),
274 .universalObservationFailureStates = std::move(universalObservationFailureStates),
275 .existentialObservationFailureStates = std::move(existentialObservationFailureStates),
276 .nonZeroTargetStateValues = std::move(nonZeroTargetStateValues),
277 .schedulerChoicesForReachingTargetStates = std::move(schedulerChoicesForReachingTargetStates),
278 .schedulerChoicesForReachingConditionStates = std::move(schedulerChoicesForReachingConditionStates)};
282template<
typename ValueType,
typename SolutionType = ValueType>
286 std::vector<uint64_t>
const& stateToFinalEc,
NormalFormData<ValueType> const& normalForm, uint64_t initialComponentIndex,
288 uint64_t chosenInitialComponentExitState, uint64_t chosenInitialComponentExit) {
294 for (uint64_t state : maybeStates) {
295 auto ecIndex = stateToFinalEc[state];
296 if (ecIndex == initialComponentIndex) {
297 initialComponentStates.
set(state,
true);
299 }
else if (ecIndex == std::numeric_limits<uint64_t>::max()) {
303 bool isEcStayChoice =
true;
304 for (
auto const& entry : transitionMatrix.
getRow(choiceIndex)) {
305 auto targetState = entry.getColumn();
306 if (stateToFinalEc[targetState] != ecIndex) {
307 isEcStayChoice =
false;
311 if (isEcStayChoice) {
312 ecStayChoices.
set(choiceIndex,
true);
318 auto const maybeNonICStatesWithoutChoice = maybeStatesWithoutChoice & ~initialComponentStates;
320 scheduler, ecStayChoices);
327 for (uint64_t state = 0; state < rowGroupCount; ++state) {
329 auto choiceIndex = scheduler.
getChoice(state).getDeterministicChoice();
330 allowedChoices.
set(rowGroups[state] + choiceIndex,
true);
331 }
else if (initialComponentStates.
get(state) || condOrTargetStates.get(state)) {
333 allowedChoices.
set(choiceIndex,
true);
340 std::stack<uint64_t> toProcess;
341 for (
auto state : condOrTargetStates) {
342 toProcess.push(state);
344 auto visitedStates = condOrTargetStates;
345 while (!toProcess.empty()) {
346 auto currentState = toProcess.top();
348 for (
auto const& entry : backwardTransitions.
getRow(currentState)) {
349 uint64_t
const predecessorState = entry.getColumn();
350 for (uint64_t
const predecessorChoice : transitionMatrix.
getRowGroupIndices(predecessorState)) {
351 if (!allowedChoices.
get(predecessorChoice) || choicesThatCanVisitCondOrTargetStates.
get(predecessorChoice)) {
354 if (
auto const r = transitionMatrix.
getRow(predecessorChoice);
355 std::none_of(r.begin(), r.end(), [¤tState](
auto const& e) { return e.getColumn() == currentState; })) {
358 choicesThatCanVisitCondOrTargetStates.
set(predecessorChoice,
true);
359 if (!visitedStates.get(predecessorState)) {
360 visitedStates.set(predecessorState,
true);
361 toProcess.push(predecessorState);
368 storm::storage::BitVector disallowedInitialComponentExits = initialComponentExitRows & choicesThatCanVisitCondOrTargetStates;
369 disallowedInitialComponentExits.
set(chosenInitialComponentExit,
false);
373 bool progress =
false;
374 for (uint64_t state : initialComponentExitStates) {
377 bool const allChoicesAreDisallowed = disallowedInitialComponentExits.
getNextUnsetIndex(groupStart) >= groupEnd;
378 if (allChoicesAreDisallowed) {
379 goodInitialComponentStates.
set(state,
false);
385 for (uint64_t state : goodInitialComponentStates) {
386 bool allChoicesAreDisallowed =
true;
388 auto row = transitionMatrix.
getRow(choiceIndex);
389 bool const hasBadSuccessor = std::any_of(
390 row.begin(), row.end(), [&goodInitialComponentStates](
auto const& entry) { return !goodInitialComponentStates.get(entry.getColumn()); });
391 if (hasBadSuccessor) {
392 choicesAllowedForInitialComponent.
set(choiceIndex,
false);
394 allChoicesAreDisallowed =
false;
397 if (allChoicesAreDisallowed) {
398 goodInitialComponentStates.set(state,
false);
405 exitStateBitvector.
set(chosenInitialComponentExitState,
true);
408 choicesAllowedForInitialComponent);
412 for (uint64_t state : initialComponentStates) {
415 if (choicesAllowedForInitialComponent.
get(choiceIndex)) {
416 scheduler.
setChoice(choiceIndex - rowGroups[state], state);
424template<
typename ValueType,
typename SolutionType = ValueType>
436 std::unique_ptr<storm::storage::Scheduler<SolutionType>>
scheduler;
443template<
typename ValueType,
typename SolutionType = ValueType>
451 auto const numMaybeStates = maybeStates.getNumberOfSetBits();
456 std::vector<ValueType> rowValues;
458 rowValues.reserve(numMaybeChoices);
459 uint64_t currentRow = 0;
460 for (
auto state : maybeStates) {
468 bool rowSumIsLess1 =
false;
469 for (
auto const& entry : transitionMatrix.
getRow(origRowIndex)) {
471 ValueType
const targetValue = normalForm.
getTargetValue(entry.getColumn());
472 targetProbability += targetValue * entry.getValue();
474 rowSumIsLess1 =
true;
477 rowSumIsLess1 =
true;
479 restartProbability += entry.getValue() * normalForm.
failProbability(entry.getColumn());
484 rowsWithSum1.
set(currentRow,
false);
486 rowValues.push_back(targetProbability);
488 for (
auto const& entry : transitionMatrix.
getRow(origRowIndex)) {
491 if (addRestartTransition && entry.getColumn() > initialState) {
492 matrixBuilder.
addNextValue(currentRow, originalToReducedStateIndexMap[initialState], restartProbability);
493 addRestartTransition =
false;
495 if (maybeStates.get(entry.getColumn())) {
496 matrixBuilder.
addNextValue(currentRow, originalToReducedStateIndexMap[entry.getColumn()], entry.getValue());
500 if (addRestartTransition) {
501 matrixBuilder.
addNextValue(currentRow, originalToReducedStateIndexMap[initialState], restartProbability);
506 STORM_LOG_ASSERT(currentRow == numMaybeChoices,
"Unexpected number of constructed rows.");
508 auto matrix = matrixBuilder.
build();
509 auto initStateInReduced = originalToReducedStateIndexMap[initialState];
515 selectedStatesInReduced.
set(initStateInReduced,
false);
516 auto ecElimResult1 =
eliminateEndComponents(selectedStatesInReduced,
true, initStateInReduced, matrix, rowsWithSum1, rowValues);
517 selectedStatesInReduced.
set(initStateInReduced,
true);
520 initStateInReduced = ecElimResult1->oldToNewStateMapping[initStateInReduced];
524 auto ecElimResult2 =
eliminateEndComponents(selectedStatesInReduced,
false, std::nullopt, matrix, rowsWithSum1, rowValues);
526 initStateInReduced = ecElimResult2->oldToNewStateMapping[initStateInReduced];
533 std::optional<std::vector<uint64_t>> reducedSchedulerChoices;
534 if (computeScheduler) {
535 reducedSchedulerChoices.emplace();
537 auto resultValue =
solveMinMaxEquationSystem(env, matrix, rowValues, rowsWithSum1, goal, initStateInReduced, reducedSchedulerChoices);
542 if (!computeScheduler) {
547 "Requested scheduler, but it was not computed or has invalid size.");
549 std::vector<uint64_t> originalRowToStateIndexMap;
551 originalRowToStateIndexMap.reserve(transitionMatrix.
getRowCount());
552 for (uint64_t originalStateIndex = 0; originalStateIndex < transitionMatrix.
getRowGroupCount(); ++originalStateIndex) {
553 originalRowToStateIndexMap.insert(originalRowToStateIndexMap.end(), transitionMatrix.
getRowGroupSize(originalStateIndex), originalStateIndex);
555 std::vector<uint64_t> reducedToOriginalRowIndexMap;
556 reducedToOriginalRowIndexMap.reserve(numMaybeChoices);
557 for (uint64_t
const originalMaybeState : maybeStates) {
558 for (
auto const originalRowIndex : transitionMatrix.
getRowGroupIndices(originalMaybeState)) {
559 reducedToOriginalRowIndexMap.push_back(originalRowIndex);
562 if (ecElimResult1.has_value() || ecElimResult2.has_value()) {
564 std::vector<uint64_t> tmpReducedToOriginalRowIndexMap;
565 tmpReducedToOriginalRowIndexMap.reserve(matrix.
getRowCount());
566 for (uint64_t reducedRow = 0; reducedRow < matrix.
getRowCount(); ++reducedRow) {
567 uint64_t intermediateRow = reducedRow;
568 if (ecElimResult2.has_value()) {
569 intermediateRow = ecElimResult2->newToOldRowMapping.at(intermediateRow);
571 if (ecElimResult1.has_value()) {
572 intermediateRow = ecElimResult1->newToOldRowMapping.at(intermediateRow);
574 tmpReducedToOriginalRowIndexMap.push_back(reducedToOriginalRowIndexMap[intermediateRow]);
576 reducedToOriginalRowIndexMap = std::move(tmpReducedToOriginalRowIndexMap);
578 for (uint64_t originalStateIndex = 0; originalStateIndex < transitionMatrix.
getRowGroupCount(); ++originalStateIndex) {
579 auto& reducedIndex = originalToReducedStateIndexMap[originalStateIndex];
580 if (maybeStates.get(originalStateIndex)) {
581 if (ecElimResult1.has_value()) {
582 reducedIndex = ecElimResult1->oldToNewStateMapping.at(reducedIndex);
584 if (ecElimResult2.has_value()) {
585 reducedIndex = ecElimResult2->oldToNewStateMapping.at(reducedIndex);
588 reducedIndex = std::numeric_limits<uint64_t>::max();
596 uint64_t
const originalRowIndex = reducedToOriginalRowIndexMap[reducedRowIndex];
597 uint64_t
const originalState = originalRowToStateIndexMap[originalRowIndex];
599 initialComponentExitRows.
set(originalRowIndex,
true);
600 initialComponentExitStates.
set(originalState,
true);
605 uint64_t chosenInitialComponentExitState = std::numeric_limits<uint64_t>::max();
606 uint64_t chosenInitialComponentExit = std::numeric_limits<uint64_t>::max();
607 auto scheduler = std::make_unique<storm::storage::Scheduler<SolutionType>>(transitionMatrix.
getRowGroupCount());
609 uint64_t reducedState = 0;
610 for (
auto const& choice : reducedSchedulerChoices.value()) {
612 uint64_t
const originalRowIndex = reducedToOriginalRowIndexMap[reducedRowIndex];
613 uint64_t
const originalState = originalRowToStateIndexMap[originalRowIndex];
614 uint64_t
const originalChoice = originalRowIndex - transitionMatrix.
getRowGroupIndices()[originalState];
615 scheduler->setChoice(originalChoice, originalState);
616 maybeStatesWithChoice.
set(originalState,
true);
617 if (reducedState == initStateInReduced) {
618 chosenInitialComponentExitState = originalState;
619 chosenInitialComponentExit = originalRowIndex;
624 auto const maybeStatesWithoutChoice = maybeStates & ~maybeStatesWithChoice;
626 originalToReducedStateIndexMap, normalForm, initStateInReduced, initialComponentExitStates, initialComponentExitRows,
627 chosenInitialComponentExitState, chosenInitialComponentExit);
629 finalResult.scheduler = std::move(scheduler);
639template<
typename ValueType,
typename SolutionType = ValueType>
656 subMatrixRowGroups.set(initialState,
false);
657 std::vector<uint64_t> dfsStack = {initialState};
658 while (!dfsStack.empty()) {
659 auto const state = dfsStack.back();
662 auto const row = transitionMatrix.
getRow(rowIndex);
663 if (std::all_of(row.begin(), row.end(),
664 [&normalForm](
auto const& entry) { return normalForm.existentialObservationFailureStates.get(entry.getColumn()); })) {
665 for (
auto const& entry : row) {
666 auto const& successor = entry.getColumn();
667 if (subMatrixRowGroups.get(successor)) {
668 subMatrixRowGroups.set(successor,
false);
669 dfsStack.push_back(successor);
673 initialComponentExitRows.set(rowIndex,
true);
674 initialComponentExitStates.set(state,
true);
678 auto const numSubmatrixRows = transitionMatrix.
getNumRowsInRowGroups(subMatrixRowGroups) + initialComponentExitRows.getNumberOfSetBits();
679 subMatrixRowGroups.set(initialState,
true);
680 auto const numSubmatrixRowGroups = subMatrixRowGroups.getNumberOfSetBits();
682 if (computeScheduler) {
683 reducedToOriginalRowIndexMap.reserve(numSubmatrixRows);
687 originalToReducedStateIndexMap = subMatrixRowGroups.getNumberOfSetBitsBeforeIndices();
688 initialStateInSubmatrix = originalToReducedStateIndexMap[initialState];
689 auto const eliminatedInitialComponentStates = normalForm.
maybeStates & ~subMatrixRowGroups;
692 for (
auto state : eliminatedInitialComponentStates) {
693 originalToReducedStateIndexMap[state] = initialStateInSubmatrix;
699 targetRowValues.reserve(numSubmatrixRows);
700 conditionRowValues.reserve(numSubmatrixRows);
701 uint64_t currentRow = 0;
702 for (
auto state : subMatrixRowGroups) {
706 auto processRow = [&](uint64_t origRowIndex) {
710 bool rowSumIsLess1 =
false;
711 for (
auto const& entry : transitionMatrix.
getRow(origRowIndex)) {
714 rowSumIsLess1 =
true;
715 ValueType
const scaledTargetValue = normalForm.
getTargetValue(entry.getColumn()) * entry.getValue();
716 targetProbability += scaledTargetValue;
718 conditionProbability += entry.getValue();
720 conditionProbability += scaledTargetValue;
722 }
else if (eliminatedInitialComponentStates.get(entry.getColumn())) {
723 rowSumIsLess1 =
true;
725 auto const columnIndex = originalToReducedStateIndexMap[entry.getColumn()];
726 matrixBuilder.
addNextValue(currentRow, columnIndex, entry.getValue());
730 rowsWithSum1.set(currentRow,
false);
732 targetRowValues.push_back(targetProbability);
733 conditionRowValues.push_back(conditionProbability);
737 if (state == initialState) {
738 for (uint64_t origRowIndex : initialComponentExitRows) {
739 processRow(origRowIndex);
740 reducedToOriginalRowIndexMap.push_back(origRowIndex);
744 processRow(origRowIndex);
745 reducedToOriginalRowIndexMap.push_back(origRowIndex);
749 submatrix = matrixBuilder.
build();
754 allExceptInit.
set(initialStateInSubmatrix,
false);
757 initialStateInSubmatrix = ecResult->oldToNewStateMapping[initialStateInSubmatrix];
760 STORM_LOG_INFO(
"Processed model has " << submatrix.getRowGroupCount() <<
" states and " << submatrix.getRowGroupCount() <<
" choices and "
761 << submatrix.getEntryCount() <<
" transitions. Matrix is " << (isAcyclic ?
"acyclic." :
"cyclic."));
763 if (computeScheduler) {
765 STORM_LOG_ASSERT(reducedToOriginalRowIndexMap.size() == numSubmatrixRows,
"Unexpected size of reducedToOriginalRowIndexMap.");
766 if (ecResult.has_value()) {
768 std::vector<uint64_t> tmpReducedToOriginalRowIndexMap;
769 tmpReducedToOriginalRowIndexMap.reserve(submatrix.getRowCount());
770 for (uint64_t reducedRow = 0; reducedRow < submatrix.getRowCount(); ++reducedRow) {
771 uint64_t intermediateRow = ecResult->newToOldRowMapping.at(reducedRow);
772 tmpReducedToOriginalRowIndexMap.push_back(reducedToOriginalRowIndexMap[intermediateRow]);
774 reducedToOriginalRowIndexMap = std::move(tmpReducedToOriginalRowIndexMap);
776 for (uint64_t originalStateIndex = 0; originalStateIndex < transitionMatrix.
getRowGroupCount(); ++originalStateIndex) {
777 auto& reducedIndex = originalToReducedStateIndexMap[originalStateIndex];
778 if (subMatrixRowGroups.get(originalStateIndex)) {
779 reducedIndex = ecResult->oldToNewStateMapping.at(reducedIndex);
781 reducedIndex = std::numeric_limits<uint64_t>::max();
787 originalToReducedStateIndexMap.clear();
788 reducedToOriginalRowIndexMap.clear();
790 initialComponentExitRows.clear();
791 initialComponentExitStates.clear();
796 ValueType
const& conditionWeight,
storm::OptionalRef<std::vector<uint64_t>> schedulerOutput = {}) {
799 auto solverEnv = env;
801 STORM_LOG_INFO(
"Using acyclic min-max solver for weighted reachability computation.");
802 solverEnv.solver().minMax().setMethod(storm::solver::MinMaxMethod::Acyclic);
805 cachedSolver->setCachingEnabled(
true);
806 cachedSolver->setRequirementsChecked();
807 cachedSolver->setHasUniqueSolution(
true);
808 cachedSolver->setHasNoEndComponents(
true);
812 cachedSolver->setTrackScheduler(schedulerOutput.has_value());
813 cachedSolver->setOptimizationDirection(dir);
816 createScaledVector(cachedB, targetWeight, targetRowValues, conditionWeight, conditionRowValues);
821 cachedSolver->solveEquations(env, cachedX, cachedB);
822 if (schedulerOutput) {
823 *schedulerOutput = cachedSolver->getSchedulerChoices();
825 return cachedX[initialStateInSubmatrix];
829 return initialStateInSubmatrix;
833 std::vector<SolutionType>& conditionResults) {
834 if (scheduler.empty()) {
835 scheduler.resize(submatrix.getRowGroupCount(), 0);
837 if (targetResults.empty()) {
840 if (conditionResults.empty()) {
843 auto solver = getScheduledSolver(env, scheduler);
845 cachedB.resize(submatrix.getRowGroupCount());
847 solver->solveEquations(env, targetResults, cachedB);
850 solver->solveEquations(env, conditionResults, cachedB);
854 STORM_LOG_ASSERT(scheduler.size() == submatrix.getRowGroupCount(),
"Scheduler size does not match number of row groups.");
855 auto solver = getScheduledSolver(env, scheduler);
856 cachedB.resize(submatrix.getRowGroupCount());
857 cachedX.resize(submatrix.getRowGroupCount());
860 solver->solveEquations(env, cachedX, cachedB);
861 SolutionType targetValue = cachedX[initialStateInSubmatrix];
864 solver->solveEquations(env, cachedX, cachedB);
865 SolutionType conditionValue = cachedX[initialStateInSubmatrix];
867 return targetValue / conditionValue;
870 template<OptimizationDirection Dir>
871 bool improveScheduler(std::vector<uint64_t>& scheduler, ValueType
const& lambda, std::vector<SolutionType>
const& targetResults,
872 std::vector<SolutionType>
const& conditionResults) {
873 bool improved =
false;
874 for (uint64_t rowGroupIndex = 0; rowGroupIndex < scheduler.size(); ++rowGroupIndex) {
876 uint64_t optimalRowIndex{0};
877 ValueType scheduledValue;
878 for (
auto rowIndex : submatrix.getRowGroupIndices(rowGroupIndex)) {
879 ValueType rowValue = targetRowValues[rowIndex] - lambda * conditionRowValues[rowIndex];
880 for (
auto const& entry : submatrix.getRow(rowIndex)) {
881 rowValue += entry.getValue() * (targetResults[entry.getColumn()] - lambda * conditionResults[entry.getColumn()]);
883 if (rowIndex == scheduler[rowGroupIndex] + submatrix.getRowGroupIndices()[rowGroupIndex]) {
884 scheduledValue = rowValue;
886 if (groupValue &= rowValue) {
887 optimalRowIndex = rowIndex;
890 if (scheduledValue != *groupValue) {
891 scheduler[rowGroupIndex] = optimalRowIndex - submatrix.getRowGroupIndices()[rowGroupIndex];
901 std::vector<uint64_t> originalRowToStateIndexMap;
903 originalRowToStateIndexMap.reserve(originalTransitionMatrix.
getRowCount());
904 for (uint64_t originalStateIndex = 0; originalStateIndex < originalTransitionMatrix.
getRowGroupCount(); ++originalStateIndex) {
905 originalRowToStateIndexMap.insert(originalRowToStateIndexMap.end(), originalTransitionMatrix.
getRowGroupSize(originalStateIndex),
910 uint64_t chosenInitialComponentExitState = std::numeric_limits<uint64_t>::max();
911 uint64_t chosenInitialComponentExit = std::numeric_limits<uint64_t>::max();
912 auto scheduler = std::make_unique<storm::storage::Scheduler<SolutionType>>(originalTransitionMatrix.
getRowGroupCount());
914 uint64_t reducedState = 0;
915 for (
auto const& choice : schedulerForReducedModel) {
916 uint64_t
const reducedRowIndex = submatrix.getRowGroupIndices()[reducedState] + choice;
917 uint64_t
const originalRowIndex = reducedToOriginalRowIndexMap[reducedRowIndex];
918 uint64_t
const originalState = originalRowToStateIndexMap[originalRowIndex];
919 uint64_t
const originalChoice = originalRowIndex - originalTransitionMatrix.
getRowGroupIndices()[originalState];
920 scheduler->setChoice(originalChoice, originalState);
921 maybeStatesWithChoice.
set(originalState,
true);
922 if (reducedState == initialStateInSubmatrix) {
923 chosenInitialComponentExitState = originalState;
924 chosenInitialComponentExit = originalRowIndex;
929 auto const maybeStatesWithoutChoice = normalForm.
maybeStates & ~maybeStatesWithChoice;
931 maybeStatesWithChoice, originalToReducedStateIndexMap, normalForm, initialStateInSubmatrix, initialComponentExitStates,
932 initialComponentExitRows, chosenInitialComponentExitState, chosenInitialComponentExit);
937 void createScaledVector(std::vector<ValueType>& out, ValueType
const& w1, std::vector<ValueType>
const& v1, ValueType
const& w2,
938 std::vector<ValueType>
const& v2)
const {
940 out.resize(v1.size());
944 auto getScheduledSolver(
storm::Environment const& env, std::vector<uint64_t>
const& scheduler)
const {
948 auto scheduledMatrix = submatrix.selectRowsFromRowGroups(scheduler, convertToEquationSystem);
949 if (convertToEquationSystem) {
950 scheduledMatrix.convertToEquationSystem();
952 auto solver = factory.
create(env, std::move(scheduledMatrix));
954 solver->setCachingEnabled(
true);
958 storm::storage::SparseMatrix<ValueType> submatrix;
959 storm::storage::BitVector rowsWithSum1;
960 std::vector<ValueType> targetRowValues;
961 std::vector<ValueType> conditionRowValues;
962 uint64_t initialStateInSubmatrix;
964 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType, SolutionType>> cachedSolver;
965 std::vector<ValueType> cachedX;
966 std::vector<ValueType> cachedB;
969 std::vector<uint64_t> originalToReducedStateIndexMap;
970 std::vector<uint64_t> reducedToOriginalRowIndexMap;
971 std::optional<typename storm::transformer::EndComponentEliminator<ValueType>::EndComponentEliminatorReturnType> ecResult;
972 storm::storage::BitVector initialComponentExitRows;
973 storm::storage::BitVector initialComponentExitStates;
976template<
typename ValueType,
typename SolutionType = ValueType>
984 "Bisection method does not adequately handle propagation of errors. Result is not necessarily sound.");
993 if (useAdvancedBounds) {
1002 std::optional<std::vector<uint64_t>> lowerScheduler, upperScheduler, middleScheduler;
1004 if (usePolicyTracking) {
1005 lowerScheduler.emplace();
1006 upperScheduler.emplace();
1007 middleScheduler.emplace();
1008 middleSchedulerRef.
reset(*middleScheduler);
1012 [[maybe_unused]] SolutionType rationalCandiate = middle;
1013 [[maybe_unused]] uint64_t rationalCandidateCount = 0;
1014 std::set<SolutionType> checkedMiddleValues;
1015 bool terminatedThroughPolicyTracking =
false;
1016 for (uint64_t iterationCount = 1;
true; ++iterationCount) {
1019 checkedMiddleValues.insert(middle);
1021 if (!useAdvancedBounds) {
1023 if (lowerBound &= middle) {
1024 lowerScheduler.swap(middleScheduler);
1028 if (upperBound &= middle) {
1029 upperScheduler.swap(middleScheduler);
1032 middle = (*lowerBound + *upperBound) / 2;
1035 if (lowerBound &= middle + (middleValue / pMax)) {
1036 lowerScheduler.swap(middleScheduler);
1038 upperBound &= middle + (middleValue / pMin);
1041 lowerBound &= middle + (middleValue / pMin);
1042 if (upperBound &= middle + (middleValue / pMax)) {
1043 upperScheduler.swap(middleScheduler);
1053 if (*lowerBound > *upperBound) {
1054 std::swap(*lowerBound, *upperBound);
1057 STORM_LOG_ASSERT(middle >= *lowerBound && middle <= *upperBound,
"Bisection method bounds are inconsistent.");
1061 SolutionType
const boundDiff = *upperBound - *lowerBound;
1062 STORM_LOG_TRACE(
"Iteration #" << iterationCount <<
":\n\t Lower bound: " << *lowerBound <<
",\n\t Upper bound: " << *upperBound
1063 <<
",\n\t Difference: " << boundDiff <<
",\n\t Middle val: " << middleValue
1064 <<
",\n\t Difference bound: " << (relative ? (precision * *lowerBound) : precision) <<
".");
1070 if (boundDiff <= (relative ? (precision * *lowerBound) : precision)) {
1071 STORM_LOG_INFO(
"Bisection method converged after " << iterationCount <<
" iterations. Difference is "
1072 << std::setprecision(std::numeric_limits<double>::digits10)
1075 }
else if (usePolicyTracking && lowerScheduler && upperScheduler && (*lowerScheduler == *upperScheduler)) {
1076 STORM_LOG_INFO(
"Bisection method converged after " << iterationCount <<
" iterations due to identical schedulers for lower and upper bound.");
1078 lowerBound &= result;
1079 upperBound &= result;
1080 terminatedThroughPolicyTracking =
true;
1085 STORM_LOG_INFO(
"Bisection method determined result after " << iterationCount <<
" iterations. Found bounds are ["
1092 STORM_LOG_WARN(
"Precision of non-exact type exceeded: Bisection method has not terminated, but the difference between upper and lower bound is "
1093 << boundDiff <<
".");
1097 STORM_LOG_WARN(
"Bisection solver aborted after " << iterationCount <<
"iterations. Bound difference is "
1109 if (rationalCandidateCount >= 4 && rationalCandiate >= *lowerBound && rationalCandiate <= *upperBound &&
1110 !checkedMiddleValues.contains(rationalCandiate)) {
1111 middle = rationalCandiate;
1112 rationalCandidateCount = 0;
1115 bool const includeLower = !checkedMiddleValues.contains(*lowerBound);
1116 bool const includeUpper = !checkedMiddleValues.contains(*upperBound);
1118 if (rationalCandiate == newRationalCandiate) {
1119 ++rationalCandidateCount;
1121 rationalCandiate = newRationalCandiate;
1122 rationalCandidateCount = 0;
1125 SolutionType delta =
1131 if (iterationCount == 8) {
1143 if (!computeScheduler) {
1147 std::vector<uint64_t> reducedSchedulerChoices;
1148 if (terminatedThroughPolicyTracking) {
1150 reducedSchedulerChoices = std::move(*lowerScheduler);
1159template<
typename ValueType,
typename SolutionType = ValueType>
1167 "Unhandled Bisection algorithm " << alg <<
".");
1170 return computeViaBisection(env, useAdvancedBounds, usePolicyTracking, initialState, goal, computeScheduler, transitionMatrix, backwardTransitions,
1174template<
typename ValueType,
typename SolutionType = ValueType>
1184 std::optional<std::vector<uint64_t>> scheduler;
1186 if (computeScheduler) {
1187 scheduler.emplace();
1188 schedulerRef.
reset(*scheduler);
1192 SolutionType outputProbability;
1201 outputProbability = threshold;
1205 if (computeScheduler) {
1212template<
typename ValueType,
typename SolutionType = ValueType>
1219 std::vector<uint64_t> scheduler;
1220 std::vector<SolutionType> targetResults, conditionResults;
1221 for (uint64_t iterationCount = 1;
true; ++iterationCount) {
1225 "Potential numerical issues: the probability to reach the target is greater than the probability to reach the condition. Difference is "
1232 bool schedulerChanged{
false};
1234 schedulerChanged = wrh.template improveScheduler<storm::OptimizationDirection::Minimize>(scheduler, lambda, targetResults, conditionResults);
1236 schedulerChanged = wrh.template improveScheduler<storm::OptimizationDirection::Maximize>(scheduler, lambda, targetResults, conditionResults);
1238 if (!schedulerChanged) {
1239 STORM_LOG_INFO(
"Policy iteration for conditional probabilities converged after " << iterationCount <<
" iterations.");
1243 STORM_LOG_WARN(
"Policy iteration for conditional probabilities converged aborted after " << iterationCount <<
"iterations.");
1249template<
typename ValueType,
typename SolutionType = ValueType>
1257 "Trying to compute undefined conditional probability: the condition has probability 0 under all policies.");
1268 return std::nullopt;
1273template<
typename ValueType,
typename SolutionType>
1280 STORM_LOG_INFO(
"Setting the conditional precision to 0 since the value type is exact and the precision was not explicitly set by the user.");
1285 auto normalFormConstructionEnv = env;
1286 auto analysisEnv = env;
1291 normalFormConstructionEnv.modelchecker().conditional().setPrecision(precision * normalFormPrecisionFactor,
false);
1294 normalFormConstructionEnv.modelchecker().conditional().setPrecision(precision,
false);
1295 analysisEnv.modelchecker().conditional().setPrecision(precision,
false);
1300 STORM_LOG_THROW(goal.hasRelevantValues(), storm::exceptions::NotSupportedException,
1301 "No initial state given. Conditional probabilities can only be computed for models with a single initial state.");
1302 STORM_LOG_THROW(goal.relevantValues().hasUniqueSetBit(), storm::exceptions::NotSupportedException,
1303 "Only one initial state is supported for conditional probabilities.");
1306 auto normalFormData =
internal::obtainNormalForm(normalFormConstructionEnv, goal.direction(), produceSchedulers, transitionMatrix, backwardTransitions,
1307 goal.relevantValues(), targetStates, conditionStates);
1309 auto const initialState = *goal.relevantValues().begin();
1311 std::unique_ptr<storm::storage::Scheduler<SolutionType>> scheduler =
nullptr;
1313 initialStateValue = *trivialValue;
1317 initialStateBitVector.set(initialState,
true);
1324 for (uint64_t state = 0; state < transitionMatrix.
getRowGroupCount(); ++state) {
1325 scheduler->setChoice(conditionReachResult.scheduler->getChoice(stateId), state);
1332 STORM_LOG_DEBUG(
"Initial state has trivial value " << initialStateValue);
1334 STORM_LOG_ASSERT(normalFormData.maybeStates.get(initialState),
"Initial state must be a maybe state if it is not a terminal state.");
1335 auto alg = analysisEnv.modelchecker().conditional().getAlgorithm();
1340 STORM_LOG_INFO(
"Analyzing normal form with " << normalFormData.maybeStates.getNumberOfSetBits() <<
" maybe states using algorithm '" << alg <<
".");
1344 auto restartEnv = analysisEnv;
1345 restartEnv.solver().minMax().setPrecision(analysisEnv.modelchecker().conditional().getPrecision());
1346 restartEnv.solver().minMax().setRelativeTerminationCriterion(analysisEnv.modelchecker().conditional().isRelativePrecision());
1356 if (goal.isBounded()) {
1357 result =
internal::decideThreshold(analysisEnv, initialState, goal.direction(), goal.thresholdValue(), produceSchedulers, transitionMatrix,
1358 backwardTransitions, normalFormData);
1370 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Unknown conditional probability algorithm: " << alg <<
".");
1374 scheduler = std::move(result.
scheduler);
1379 if (produceSchedulers && scheduler) {
1381 targetStates, *scheduler);
1383 conditionStates, *scheduler);
1386 for (uint64_t state = 0; state < transitionMatrix.
getRowGroupCount(); ++state) {
1387 if (!scheduler->isChoiceSelected(state)) {
1389 scheduler->setChoice(0, state);
1396 memoryStateLabeling.
addLabel(
"init_memory");
1397 memoryStateLabeling.
addLabel(
"condition_reached");
1398 memoryStateLabeling.
addLabel(
"target_reached");
1407 for (uint64_t state : conditionStates) {
1409 for (
auto entryIt = transitionMatrix.
getRow(choice).
begin(); entryIt < transitionMatrix.
getRow(choice).
end(); ++entryIt) {
1410 conditionExitTransitions.
set(entryIt - transitionMatrix.
begin(),
true);
1414 for (uint64_t state : targetStates) {
1416 for (
auto entryIt = transitionMatrix.
getRow(choice).
begin(); entryIt < transitionMatrix.
getRow(choice).
end(); ++entryIt) {
1417 targetExitTransitions.
set(entryIt - transitionMatrix.
begin(),
true);
1422 memoryTransitions[0][0] =
1423 allTransitions & ~conditionExitTransitions & ~targetExitTransitions;
1424 memoryTransitions[0][1] = conditionExitTransitions;
1425 memoryTransitions[0][2] = targetExitTransitions & ~conditionExitTransitions;
1426 memoryTransitions[1][1] = allTransitions;
1427 memoryTransitions[2][2] = allTransitions;
1432 auto finalScheduler = std::unique_ptr<storm::storage::Scheduler<SolutionType>>(
1435 for (uint64_t state = 0; state < transitionMatrix.
getRowGroupCount(); ++state) {
1437 if (conditionStates.get(state)) {
1438 if (normalFormData.schedulerChoicesForReachingTargetStates->isChoiceSelected(state)) {
1439 finalScheduler->setChoice(normalFormData.schedulerChoicesForReachingTargetStates->getChoice(state), state, 0);
1441 finalScheduler->setChoice(0, state, 0);
1443 }
else if (targetStates.get(state)) {
1444 if (normalFormData.schedulerChoicesForReachingConditionStates->isChoiceSelected(state)) {
1445 finalScheduler->setChoice(normalFormData.schedulerChoicesForReachingConditionStates->getChoice(state), state, 0);
1447 finalScheduler->setChoice(0, state, 0);
1450 finalScheduler->setChoice(scheduler->getChoice(state), state, 0);
1454 if (normalFormData.schedulerChoicesForReachingTargetStates->isChoiceSelected(state)) {
1455 finalScheduler->setChoice(normalFormData.schedulerChoicesForReachingTargetStates->getChoice(state), state, 1);
1457 finalScheduler->setChoice(0, state, 1);
1460 if (normalFormData.schedulerChoicesForReachingConditionStates->isChoiceSelected(state)) {
1461 finalScheduler->setChoice(normalFormData.schedulerChoicesForReachingConditionStates->getChoice(state), state, 2);
1463 finalScheduler->setChoice(0, state, 2);
1467 result->asExplicitQuantitativeCheckResult<SolutionType>().setScheduler(std::move(finalScheduler));
1479 bool produceSchedulers,
bool isPrecisionSetFromDefault() const
bool isRelativePrecision() const
storm::RationalNumber getPrecision() const
SolverEnvironment & solver()
ModelCheckerEnvironment & modelchecker()
void setPrecision(storm::RationalNumber value)
ConditionalModelCheckerEnvironment & conditional()
Helper class that optionally holds a reference to an object of type T.
void reset()
Unsets the reference.
MinMaxSolverEnvironment & minMax()
bool isForceSoundness() const
A quantitative check result over the states of a sparse model.
static MDPSparseModelCheckingHelperReturnType< SolutionType > computeUntilProbabilities(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool qualitative, bool produceScheduler, ModelCheckerHint const &hint=ModelCheckerHint())
A helper class that computes (weighted) reachability probabilities for a given MDP in normal form.
bool improveScheduler(std::vector< uint64_t > &scheduler, ValueType const &lambda, std::vector< SolutionType > const &targetResults, std::vector< SolutionType > const &conditionResults)
void evaluateScheduler(storm::Environment const &env, std::vector< uint64_t > &scheduler, std::vector< SolutionType > &targetResults, std::vector< SolutionType > &conditionResults)
SolutionType evaluateScheduler(storm::Environment const &env, std::vector< uint64_t > const &scheduler)
SolutionType computeWeightedDiff(storm::Environment const &env, storm::OptimizationDirection const dir, ValueType const &targetWeight, ValueType const &conditionWeight, storm::OptionalRef< std::vector< uint64_t > > schedulerOutput={})
WeightedReachabilityHelper(uint64_t const initialState, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, NormalFormData< ValueType > const &normalForm, bool computeScheduler)
std::unique_ptr< storm::storage::Scheduler< ValueType > > constructSchedulerForInputModel(std::vector< uint64_t > const &schedulerForReducedModel, storm::storage::SparseMatrix< ValueType > const &originalTransitionMatrix, storm::storage::SparseMatrix< ValueType > const &originalBackwardTransitions, NormalFormData< ValueType > const &normalForm) const
auto getInternalInitialState() const
void addLabel(std::string const &label)
Adds a new label to the labelings.
This class manages the labeling of the state space with a number of (atomic) labels.
void addLabelToState(std::string const &label, storm::storage::sparse::state_type state)
Adds a label to a given state.
virtual std::unique_ptr< LinearEquationSolver< ValueType > > create(Environment const &env) const override
Creates an equation solver with the current settings, but without a matrix.
virtual std::unique_ptr< MinMaxLinearEquationSolver< ValueType, SolutionType > > create(Environment const &env) const override
virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const &env) const
Retrieves the problem format that the solver expects if it was created with the current settings.
bool boundIsStrict() const
bool boundIsALowerBound() const
SolutionType const & thresholdValue() const
OptimizationDirection direction() const
storm::logic::ComparisonType boundComparisonType() const
A bit vector that is internally represented as a vector of 64-bit values.
std::vector< uint64_t > getNumberOfSetBitsBeforeIndices() const
Retrieves a vector that holds at position i the number of bits set before index i.
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
uint64_t getNextUnsetIndex(uint64_t startingIndex) const
Retrieves the index of the bit that is the next bit set to false in the bit vector.
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
const_iterator begin() const
Returns an iterator to the indices of the set bits in the bit vector.
size_t size() const
Retrieves the number of bits this bit vector can store.
void resize(uint64_t newLength, bool init=false)
Resizes the bit vector to hold the given new number of bits.
bool get(uint64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
This class represents the decomposition of a nondeterministic model into its maximal end components.
This class represents a (deterministic) memory structure that can be used to encode certain events (s...
std::vector< std::vector< boost::optional< storm::storage::BitVector > > > TransitionMatrix
This class defines which action is chosen in a particular state of a non-deterministic model.
SchedulerChoice< ValueType > const & getChoice(uint_fast64_t modelState, uint_fast64_t memoryState=0) const
Gets the choice defined by the scheduler for the given model and memory state.
void setChoice(SchedulerChoice< ValueType > const &choice, uint_fast64_t modelState, uint_fast64_t memoryState=0)
Sets the choice defined by the scheduler for the given state.
bool isChoiceSelected(BitVector const &selectedStates, uint64_t memoryState=0) const
Is the scheduler defined on the states indicated by the selected-states bitvector?
const_iterator end() const
Retrieves an iterator that points past the last entry of the rows.
const_iterator begin() const
Retrieves an iterator that points to the beginning of the rows.
A class that can be used to build a sparse matrix by adding value by value.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
void newRowGroup(index_type startingRow)
Starts a new row group in the matrix.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
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.
index_type getEntryCount() const
Returns the number of entries in the matrix.
index_type getNumRowsInRowGroups(storm::storage::BitVector const &groupConstraint) const
Returns the total number of rows that are in one of the specified row groups.
SparseMatrix getSubmatrix(bool useGroups, storm::storage::BitVector const &rowConstraint, storm::storage::BitVector const &columnConstraint, bool insertDiagonalEntries=false, storm::storage::BitVector const &makeZeroColumns=storm::storage::BitVector()) const
Creates a submatrix of the current matrix by dropping all rows and columns whose bits are not set to ...
const_iterator begin(index_type row) const
Retrieves an iterator that points to the beginning of the given row.
index_type getRowGroupCount() const
Returns the number of row groups in the matrix.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
index_type getRowGroupSize(index_type group) const
Returns the size of the given row group.
storm::storage::SparseMatrix< value_type > transpose(bool joinGroups=false, bool keepZeros=false) const
Transposes the matrix.
index_type getRowCount() const
Returns the number of rows of the matrix.
Stores and manages an extremal (maximal or minimal) value.
#define STORM_LOG_INFO(message)
#define STORM_LOG_WARN(message)
#define STORM_LOG_DEBUG(message)
#define STORM_LOG_TRACE(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_WARN_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
std::unique_ptr< storm::storage::Scheduler< ValueType > > computeReachabilityProbabilities(Environment const &env, std::map< uint64_t, ValueType > &nonZeroResults, storm::solver::OptimizationDirection const dir, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::BitVector const &initialStates, storm::storage::BitVector const &allowedStates, storm::storage::BitVector const &targetStates, bool computeScheduler=true)
Computes the reachability probabilities for the given target states and inserts all non-zero values i...
NormalFormData< ValueType > obtainNormalForm(Environment const &env, storm::solver::OptimizationDirection const dir, bool computeScheduler, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &relevantStates, storm::storage::BitVector const &targetStates, storm::storage::BitVector const &conditionStates)
std::optional< typename storm::transformer::EndComponentEliminator< ValueType >::EndComponentEliminatorReturnType > eliminateEndComponents(storm::storage::BitVector const &possibleEcStates, bool addRowAtRepresentativeState, std::optional< uint64_t > const representativeRowEntry, storm::storage::SparseMatrix< ValueType > &matrix, storm::storage::BitVector &rowsWithSum1, std::vector< ValueType > &rowValues1, storm::OptionalRef< std::vector< ValueType > > rowValues2={})
internal::ResultReturnType< ValueType > computeViaRestartMethod(Environment const &env, uint64_t const initialState, storm::solver::SolveGoal< ValueType, SolutionType > const &goal, bool computeScheduler, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, NormalFormData< ValueType > const &normalForm)
Uses the restart method by Baier et al.
internal::ResultReturnType< SolutionType > computeViaPolicyIteration(Environment const &env, uint64_t const initialState, storm::solver::OptimizationDirection const dir, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, NormalFormData< ValueType > const &normalForm)
SolutionType solveMinMaxEquationSystem(storm::Environment const &env, storm::storage::SparseMatrix< ValueType > const &matrix, std::vector< ValueType > const &rowValues, storm::storage::BitVector const &rowsWithSum1, storm::solver::SolveGoal< ValueType, SolutionType > const &goal, uint64_t const initialState, std::optional< std::vector< uint64_t > > &schedulerOutput)
internal::ResultReturnType< ValueType > computeViaBisection(Environment const &env, bool const useAdvancedBounds, bool const usePolicyTracking, uint64_t const initialState, storm::solver::SolveGoal< ValueType, SolutionType > const &goal, bool computeScheduler, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, NormalFormData< ValueType > const &normalForm)
std::optional< SolutionType > handleTrivialCases(uint64_t const initialState, NormalFormData< ValueType > const &normalForm)
internal::ResultReturnType< ValueType > decideThreshold(Environment const &env, uint64_t const initialState, storm::OptimizationDirection const &direction, SolutionType const &threshold, bool computeScheduler, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, NormalFormData< ValueType > const &normalForm)
void finalizeSchedulerForMaybeStates(storm::storage::Scheduler< SolutionType > &scheduler, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &maybeStates, storm::storage::BitVector const &maybeStatesWithoutChoice, storm::storage::BitVector const &maybeStatesWithChoice, std::vector< uint64_t > const &stateToFinalEc, NormalFormData< ValueType > const &normalForm, uint64_t initialComponentIndex, storm::storage::BitVector const &initialComponentExitStates, storm::storage::BitVector const &initialComponentExitRows, uint64_t chosenInitialComponentExitState, uint64_t chosenInitialComponentExit)
std::unique_ptr< CheckResult > computeConditionalProbabilities(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, bool produceSchedulers, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &targetStates, storm::storage::BitVector const &conditionStates)
std::unique_ptr< storm::solver::MinMaxLinearEquationSolver< ValueType, SolutionType > > configureMinMaxLinearEquationSolver(Environment const &env, SolveGoal< ValueType, SolutionType > &&goal, storm::solver::MinMaxLinearEquationSolverFactory< ValueType, SolutionType > const &factory, MatrixType &&matrix, OptimizationDirectionSetting optimizationDirectionSetting=OptimizationDirectionSetting::Unset)
bool constexpr minimize(OptimizationDirection d)
void computeSchedulerProbGreater0E(storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, storm::storage::Scheduler< SchedulerValueType > &scheduler, boost::optional< storm::storage::BitVector > const &rowFilter)
Computes a scheduler for the ProbGreater0E-States such that in the induced system the given psiStates...
storm::storage::BitVector getReachableStates(storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::BitVector const &initialStates, storm::storage::BitVector const &constraintStates, storm::storage::BitVector const &targetStates, bool useStepBound, uint_fast64_t maximalSteps, boost::optional< storm::storage::BitVector > const &choiceFilter)
Performs a forward depth-first search through the underlying graph structure to identify the states t...
void computeSchedulerProb1E(storm::storage::BitVector const &prob1EStates, storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, storm::storage::Scheduler< SchedulerValueType > &scheduler, boost::optional< storm::storage::BitVector > const &rowFilter)
Computes a scheduler for the given prob1EStates such that in the induced system the given psiStates a...
bool hasCycle(storm::storage::SparseMatrix< T > const &transitionMatrix, boost::optional< storm::storage::BitVector > const &subsystem)
Returns true if the graph represented by the given matrix has a cycle.
storm::storage::BitVector performProb1A(storm::models::sparse::NondeterministicModel< T, RM > const &model, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Computes the sets of states that have probability 1 of satisfying phi until psi under all possible re...
storm::storage::BitVector performProb0A(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
storm::storage::BitVector performProb0E(storm::models::sparse::NondeterministicModel< T, RM > const &model, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Computes the sets of states that have probability 0 of satisfying phi until psi under at least one po...
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
void selectVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< T > const &values)
Selects the elements from a vector at the specified positions and writes them consecutively into anot...
void applyPointwise(std::vector< InValueType1 > const &firstOperand, std::vector< InValueType2 > const &secondOperand, std::vector< OutValueType > &target, Operation f=Operation())
Applies the given operation pointwise on the two given vectors and writes the result to the third vec...
bool isOne(ValueType const &a)
Extremum< storm::OptimizationDirection::Maximize, ValueType > Maximum
Extremum< storm::OptimizationDirection::Minimize, ValueType > Minimum
bool isAlmostZero(ValueType const &a)
bool isZero(ValueType const &a)
storm::RationalNumber findRational(storm::RationalNumber const &lowerBound, bool lowerInclusive, storm::RationalNumber const &upperBound, bool upperInclusive)
Finds the "simplest" rational number in the given interval, where "simplest" means having the smalles...
TargetType convertNumber(SourceType const &number)
solver::OptimizationDirection OptimizationDirection
ConditionalAlgorithmSetting
@ BisectionPolicyTracking
@ BisectionAdvancedPolicyTracking
static const bool IsExact
ResultReturnType(ValueType initialStateValue, std::unique_ptr< storm::storage::Scheduler< ValueType > > &&scheduler=nullptr)
bool hasScheduler() const
std::unique_ptr< storm::storage::Scheduler< SolutionType > > scheduler
ValueType initialStateValue