33template<
typename ValueType,
typename SolutionType>
36 : linearEquationSolverFactory(
std::move(linearEquationSolverFactory)) {
40template<
typename ValueType,
typename SolutionType>
47template<
typename ValueType,
typename SolutionType>
54template<
typename ValueType,
typename SolutionType>
55MinMaxMethod IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::getMethod(
Environment const& env,
bool isExactMode)
const {
59 if (isExactMode && method != MinMaxMethod::PolicyIteration && method != MinMaxMethod::RationalSearch && method != MinMaxMethod::ViToPi) {
62 "Selecting 'Policy iteration' as the solution technique to guarantee exact results. If you want to override this, please explicitly specify a "
64 method = MinMaxMethod::PolicyIteration;
66 STORM_LOG_WARN(
"The selected solution method " <<
toString(method) <<
" does not guarantee exact results.");
68 }
else if (env.
solver().
isForceSoundness() && method != MinMaxMethod::SoundValueIteration && method != MinMaxMethod::IntervalIteration &&
69 method != MinMaxMethod::PolicyIteration && method != MinMaxMethod::RationalSearch && method != MinMaxMethod::OptimisticValueIteration &&
70 method != MinMaxMethod::GuessingValueIteration) {
72 method = MinMaxMethod::OptimisticValueIteration;
76 <<
"' as the solution technique to guarantee sound results. If you want to override this, please explicitly specify a different method.");
78 STORM_LOG_WARN(
"The selected solution method does not guarantee sound results.");
84 STORM_LOG_WARN(
"Selected method is not supported for this solver and interval models, switching to robust value iteration.");
85 method = MinMaxMethod::ValueIteration;
88 STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch ||
89 method == MinMaxMethod::SoundValueIteration || method == MinMaxMethod::IntervalIteration ||
90 method == MinMaxMethod::OptimisticValueIteration || method == MinMaxMethod::GuessingValueIteration || method == MinMaxMethod::ViToPi,
91 storm::exceptions::InvalidEnvironmentException,
"This solver does not support the selected method '" <<
toString(method) <<
"'.");
95template<
typename ValueType,
typename SolutionType>
97 std::vector<SolutionType>& x, std::vector<ValueType>
const& b)
const {
100 case MinMaxMethod::ValueIteration:
101 result = solveEquationsValueIteration(env, dir, x, b);
103 case MinMaxMethod::OptimisticValueIteration:
104 result = solveEquationsOptimisticValueIteration(env, dir, x, b);
106 case MinMaxMethod::GuessingValueIteration:
107 result = solveEquationsGuessingValueIteration(env, dir, x, b);
109 case MinMaxMethod::PolicyIteration:
110 result = solveEquationsPolicyIteration(env, dir, x, b);
112 case MinMaxMethod::RationalSearch:
113 result = solveEquationsRationalSearch(env, dir, x, b);
115 case MinMaxMethod::IntervalIteration:
116 result = solveEquationsIntervalIteration(env, dir, x, b);
118 case MinMaxMethod::SoundValueIteration:
119 result = solveEquationsSoundValueIteration(env, dir, x, b);
121 case MinMaxMethod::ViToPi:
122 result = solveEquationsViToPi(env, dir, x, b);
125 STORM_LOG_THROW(
false, storm::exceptions::InvalidEnvironmentException,
"This solver does not implement the selected solution method");
131template<
typename ValueType,
typename SolutionType>
132void IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::setUpViOperator()
const {
133 if (!viOperatorTriv && !viOperatorNontriv) {
134 if (this->A->hasTrivialRowGrouping()) {
136 viOperatorTriv = std::make_shared<helper::ValueIterationOperator<ValueType, true, SolutionType>>();
137 viOperatorTriv->setMatrixBackwards(*this->A);
143 viOperatorNontriv = std::make_shared<helper::ValueIterationOperator<ValueType, false, SolutionType>>();
144 viOperatorNontriv->setMatrixBackwards(*this->A);
148 viOperatorNontriv = std::make_shared<helper::ValueIterationOperator<ValueType, false, SolutionType>>();
149 viOperatorNontriv->setMatrixBackwards(*this->A);
152 if (this->choiceFixedForRowGroup) {
154 assert(this->initialScheduler);
155 auto callback = [&](uint64_t groupIndex, uint64_t localRowIndex) {
156 return this->choiceFixedForRowGroup->get(groupIndex) && this->initialScheduler->at(groupIndex) != localRowIndex;
158 if (viOperatorTriv) {
159 viOperatorTriv->setIgnoredRows(
true, callback);
161 if (viOperatorNontriv) {
162 viOperatorNontriv->setIgnoredRows(
true, callback);
167template<
typename ValueType,
typename SolutionType>
168void IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::extractScheduler(std::vector<SolutionType>& x, std::vector<ValueType>
const& b,
173 if (!this->robustSchedulerIndex) {
174 this->robustSchedulerIndex = std::vector<uint64_t>(x.size(), 0);
176 this->robustSchedulerIndex->resize(x.size(), 0);
178 uint64_t numSchedulerChoices = 0;
179 for (uint64_t row = 0; row < this->A->getRowCount(); ++row) {
180 this->robustSchedulerIndex->at(row) = numSchedulerChoices;
181 numSchedulerChoices += this->A->getRow(row).getNumberOfEntries();
184 if (!this->schedulerChoices) {
185 this->schedulerChoices = std::vector<uint64_t>(numSchedulerChoices, 0);
187 this->schedulerChoices->resize(numSchedulerChoices, 0);
191 if (!this->schedulerChoices) {
192 this->schedulerChoices = std::vector<uint64_t>(x.size(), 0);
194 this->schedulerChoices->resize(x.size(), 0);
199 if (!viOperatorTriv && !viOperatorNontriv) {
200 STORM_LOG_WARN(
"Expected VI operator to be initialized for scheduler extraction. Initializing now, but this is inefficient.");
203 if (viOperatorTriv) {
205 storm::solver::helper::SchedulerTrackingHelper<ValueType, SolutionType, true> schedHelper(viOperatorTriv);
206 schedHelper.computeScheduler(x, b, dir, *this->schedulerChoices, uncertaintyResolutionMode, updateX ? &x :
nullptr, this->robustSchedulerIndex);
208 STORM_LOG_ERROR(
"SchedulerTrackingHelper not implemented for this setting (trivial row grouping but not Interval->double).");
211 if (viOperatorNontriv) {
212 storm::solver::helper::SchedulerTrackingHelper<ValueType, SolutionType, false> schedHelper(viOperatorNontriv);
213 schedHelper.computeScheduler(x, b, dir, *this->schedulerChoices, uncertaintyResolutionMode, updateX ? &x :
nullptr, this->robustSchedulerIndex);
217template<
typename ValueType,
typename SolutionType>
218bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveInducedEquationSystem(
220 std::vector<SolutionType>& x, std::vector<ValueType>& subB, std::vector<ValueType>
const& originalB,
OptimizationDirection dir)
const {
224 "We did not implement solving induced equation systems for interval-based models outside of robust VI.");
228 STORM_LOG_ASSERT(subB.size() == x.size(),
"Sizes of subB and x do not coincide.");
229 STORM_LOG_ASSERT(this->linearEquationSolverFactory !=
nullptr,
"Wrong constructor was called.");
231 storm::exceptions::NotImplementedException,
"Solving induced system of Interval Model not supported for the selected equation solver");
233 storm::storage::SparseMatrixBuilder<SolutionType> newMatrixBuilder(this->A->getRowCount(), this->A->getColumnCount(), this->A->getEntryCount());
236 auto schedulerIterator = scheduler.begin();
237 for (uint64_t rowIndex = 0; rowIndex < this->A->getRowCount(); rowIndex++) {
238 auto const& row = this->A->getRow(rowIndex);
240 static std::vector<SolutionType> tmp;
245 for (
auto const& entry : row) {
246 tmp.push_back(entry.getValue().lower());
247 probLeft -= entry.getValue().lower();
250 auto const& rowIter = row.begin();
251 for (uint64_t i = 0;
i < row.getNumberOfEntries();
i++, schedulerIterator++) {
253 auto const& entry = rowIter[*schedulerIterator];
254 SolutionType
const diameter = entry.getValue().upper() - entry.getValue().lower();
256 tmp[*schedulerIterator] += value;
263 for (uint64_t i = 0;
i < row.getNumberOfEntries();
i++) {
264 auto const& entry = rowIter[
i];
265 newMatrixBuilder.addNextValue(rowIndex, entry.getColumn(), tmp[i]);
268 STORM_LOG_ASSERT(schedulerIterator == scheduler.end(),
"Offset issue in scheduler?");
272 std::vector<SolutionType> b;
273 for (
auto const& entry : subB) {
274 if (dir == OptimizationDirection::Maximize) {
275 b.push_back(entry.upper());
277 b.push_back(entry.lower());
281 auto const submatrix = newMatrixBuilder.build();
284 if (!linearEquationSolver) {
286 linearEquationSolver = this->linearEquationSolverFactory->create(env, std::move(submatrix));
287 linearEquationSolver->setBoundsFromOtherSolver(*
this);
288 linearEquationSolver->setCachingEnabled(
true);
291 linearEquationSolver->setMatrix(std::move(submatrix));
294 return linearEquationSolver->solveEquations(env, x, b);
296 STORM_LOG_ASSERT(subB.size() == x.size(),
"Sizes of subB and x do not coincide.");
297 STORM_LOG_ASSERT(this->linearEquationSolverFactory !=
nullptr,
"Wrong constructor was called.");
301 storm::storage::SparseMatrix<ValueType> submatrix;
304 if (convertToEquationSystem) {
310 if (!linearEquationSolver) {
312 linearEquationSolver = this->linearEquationSolverFactory->create(env, std::move(submatrix));
313 linearEquationSolver->setBoundsFromOtherSolver(*
this);
314 linearEquationSolver->setCachingEnabled(
true);
317 linearEquationSolver->setMatrix(std::move(submatrix));
320 return linearEquationSolver->solveEquations(env, x, subB);
324template<
typename ValueType,
typename SolutionType>
325bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsPolicyIteration(Environment
const& env,
OptimizationDirection dir,
326 std::vector<SolutionType>& x,
327 std::vector<ValueType>
const& b)
const {
328 std::vector<storm::storage::sparse::state_type> scheduler =
329 this->hasInitialScheduler() ? this->getInitialScheduler() : std::vector<storm::storage::sparse::
state_type>(this->A->getRowGroupCount());
330 return performPolicyIteration(env, dir, x, b, std::move(scheduler));
333template<
typename ValueType,
typename SolutionType>
334bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::performPolicyIteration(
335 Environment
const& env,
OptimizationDirection dir, std::vector<SolutionType>& x, std::vector<ValueType>
const& b,
336 std::vector<storm::storage::sparse::state_type>&& initialPolicy)
const {
338 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"We did not implement policy iteration for interval-based models.");
341 std::vector<storm::storage::sparse::state_type> scheduler = std::move(initialPolicy);
343 if (!auxiliaryRowGroupVector) {
344 auxiliaryRowGroupVector = std::make_unique<std::vector<ValueType>>(this->A->getRowGroupCount());
346 std::vector<ValueType>& subB = *auxiliaryRowGroupVector;
349 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver;
351 std::unique_ptr<storm::Environment> environmentOfSolverStorage;
352 auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType());
354 bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision();
355 bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion();
356 if (changePrecision || changeRelative) {
357 environmentOfSolverStorage = std::make_unique<storm::Environment>(env);
358 boost::optional<storm::RationalNumber> newPrecision;
359 boost::optional<bool> newRelative;
360 if (changePrecision) {
361 newPrecision = env.solver().minMax().getPrecision();
363 if (changeRelative) {
366 environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative);
369 storm::Environment
const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env;
372 uint64_t iterations = 0;
373 this->startMeasureProgress();
376 solveInducedEquationSystem(environmentOfSolver, solver, scheduler, x, subB, b, dir);
379 bool schedulerImproved =
false;
381 for (uint_fast64_t group = 0; group < this->A->getRowGroupCount(); ++group) {
382 if (!this->choiceFixedForRowGroup || !this->choiceFixedForRowGroup.get()[group]) {
384 uint_fast64_t currentChoice = scheduler[group];
385 for (uint_fast64_t choice = this->A->getRowGroupIndices()[group]; choice < this->A->getRowGroupIndices()[group + 1]; ++choice) {
387 if (choice - this->A->getRowGroupIndices()[group] == currentChoice) {
393 for (
auto const& entry : this->A->getRow(choice)) {
394 choiceValue += entry.getValue() * x[entry.getColumn()];
396 choiceValue += b[choice];
401 if (valueImproved(dir, x[group], choiceValue)) {
402 schedulerImproved =
true;
403 scheduler[group] = choice - this->A->getRowGroupIndices()[group];
404 x[group] = std::move(choiceValue);
411 if (!schedulerImproved) {
419 iterations, env.solver().minMax().getMaximalNumberOfIterations());
422 this->showProgressIterative(iterations);
426 this->reportStatus(status, iterations);
429 if (this->isTrackSchedulerSet()) {
430 this->schedulerChoices = std::move(scheduler);
433 if (!this->isCachingEnabled()) {
441template<
typename ValueType,
typename SolutionType>
442bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::valueImproved(
OptimizationDirection dir, ValueType
const& value1,
443 ValueType
const& value2)
const {
444 if (dir == OptimizationDirection::Minimize) {
445 return value2 < value1;
447 return value2 > value1;
451template<
typename ValueType,
typename SolutionType>
457 bool needsLinEqSolver =
false;
458 needsLinEqSolver |= method == MinMaxMethod::PolicyIteration;
459 needsLinEqSolver |= method == MinMaxMethod::ValueIteration && (this->hasInitialScheduler() ||
hasInitialScheduler);
460 needsLinEqSolver |= method == MinMaxMethod::ViToPi;
464 STORM_LOG_ASSERT(!needsLinEqSolver,
"Intervals should not require a linear equation solver.");
466 }
else if (needsLinEqSolver) {
472 if (method == MinMaxMethod::ValueIteration) {
487 }
else if (method == MinMaxMethod::OptimisticValueIteration) {
494 }
else if (method == MinMaxMethod::GuessingValueIteration) {
500 }
else if (method == MinMaxMethod::IntervalIteration) {
506 }
else if (method == MinMaxMethod::RationalSearch) {
515 }
else if (method == MinMaxMethod::PolicyIteration) {
523 }
else if (method == MinMaxMethod::SoundValueIteration) {
528 }
else if (method == MinMaxMethod::ViToPi) {
534 STORM_LOG_THROW(
false, storm::exceptions::InvalidEnvironmentException,
"Unsupported technique for iterative MinMax linear equation solver.");
539template<
typename ValueType,
typename SolutionType>
542 auto oldValueIt = oldValues.begin();
543 for (
auto value : relevantValues) {
550template<
typename ValueType,
typename SolutionType>
551ValueType
computeMaxAbsDiff(std::vector<ValueType>
const& allOldValues, std::vector<ValueType>
const& allNewValues,
554 for (
auto value : relevantValues) {
560template<
typename ValueType,
typename SolutionType>
562 std::vector<SolutionType>& x,
563 std::vector<ValueType>
const& b)
const {
565 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"We did not implement optimistic value iteration for interval-based models.");
571 if (this->isTrackSchedulerSet()) {
572 this->schedulerChoices = std::vector<uint_fast64_t>(x.size(), 0);
581 std::optional<ValueType> lowerBound, upperBound;
582 if (this->hasLowerBound()) {
583 lowerBound = this->getLowerBound(
true);
585 if (this->hasUpperBound()) {
586 upperBound = this->getUpperBound(
true);
588 uint64_t numIterations{0};
589 auto oviCallback = [&](
SolverStatus const& current, std::vector<ValueType>
const& v) {
590 this->showProgressIterative(numIterations);
593 this->createLowerBoundsVector(x);
594 std::optional<ValueType> guessingFactor;
598 this->startMeasureProgress();
600 upperBound, oviCallback);
601 this->reportStatus(status, numIterations);
604 if (this->isTrackSchedulerSet()) {
605 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
608 if (!this->isCachingEnabled()) {
616template<
typename ValueType,
typename SolutionType>
617bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsGuessingValueIteration(Environment
const& env,
OptimizationDirection dir,
618 std::vector<SolutionType>& x,
619 std::vector<ValueType>
const& b)
const {
621 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"We did not implement guessing value iteration for interval-based models.");
627 auto upperX = std::make_unique<std::vector<SolutionType>>(x.size());
629 storm::solver::helper::GuessingValueIterationHelper<ValueType, false>
helper(viOperatorNontriv, *this->A);
631 uint64_t numIterations{0};
634 this->showProgressIterative(numIterations);
635 bool terminateEarly = this->hasCustomTerminationCondition() && this->getTerminationCondition().terminateNow(data.x,
SolverGuarantee::LessOrEqual) &&
637 return this->updateStatus(data.status, terminateEarly, numIterations, env.solver().minMax().getMaximalNumberOfIterations());
640 this->createLowerBoundsVector(lowerX);
641 this->createUpperBoundsVector(*upperX);
643 this->startMeasureProgress();
644 auto statusIters =
helper.solveEquations(lowerX, *upperX, b, numIterations,
648 lowerX, *upperX, x, [&two](ValueType
const& first, ValueType
const& second) -> ValueType {
return (first + second) / two; });
650 this->reportStatus(statusIters, numIterations);
653 if (this->isTrackSchedulerSet()) {
654 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
657 if (!this->isCachingEnabled()) {
665template<
typename ValueType,
typename SolutionType>
666bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsValueIteration(Environment
const& env,
OptimizationDirection dir,
667 std::vector<SolutionType>& x,
668 std::vector<ValueType>
const& b)
const {
673 if (this->hasInitialScheduler()) {
674 if (!auxiliaryRowGroupVector) {
675 auxiliaryRowGroupVector = std::make_unique<std::vector<ValueType>>(this->A->getRowGroupCount());
678 std::unique_ptr<storm::solver::LinearEquationSolver<SolutionType>> linEqSolver;
680 std::unique_ptr<storm::Environment> environmentOfSolverStorage;
681 auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType());
683 bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision();
684 bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion();
685 if (changePrecision || changeRelative) {
686 environmentOfSolverStorage = std::make_unique<storm::Environment>(env);
687 boost::optional<storm::RationalNumber> newPrecision;
688 boost::optional<bool> newRelative;
689 if (changePrecision) {
690 newPrecision = env.solver().minMax().getPrecision();
692 if (changeRelative) {
695 environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative);
698 storm::Environment
const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env;
700 bool success = solveInducedEquationSystem(environmentOfSolver, linEqSolver, this->getInitialScheduler(), x, *auxiliaryRowGroupVector, b, dir);
708 }
else if (!this->hasUniqueSolution()) {
710 this->createLowerBoundsVector(x);
713 this->createUpperBoundsVector(x);
716 }
else if (this->hasCustomTerminationCondition()) {
718 this->createLowerBoundsVector(x);
721 this->createUpperBoundsVector(x);
726 uint64_t numIterations{0};
728 this->showProgressIterative(numIterations);
729 return this->updateStatus(current, x, guarantee, numIterations, env.solver().minMax().getMaximalNumberOfIterations());
731 this->startMeasureProgress();
733 if (this->A->hasTrivialRowGrouping()) {
734 storm::solver::helper::ValueIterationHelper<ValueType, true, SolutionType> viHelper(viOperatorTriv);
736 auto status = viHelper.VI(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(),
738 env.solver().minMax().getMultiplicationStyle(), this->getUncertaintyResolutionMode());
739 this->reportStatus(status, numIterations);
742 if (this->isTrackSchedulerSet()) {
743 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
746 if (!this->isCachingEnabled()) {
752 storm::solver::helper::ValueIterationHelper<ValueType, false, SolutionType> viHelper(viOperatorNontriv);
754 auto status = viHelper.VI(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(),
756 env.solver().minMax().getMultiplicationStyle(), this->getUncertaintyResolutionMode());
757 this->reportStatus(status, numIterations);
760 if (this->isTrackSchedulerSet()) {
761 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
764 if (!this->isCachingEnabled()) {
772template<
typename ValueType,
typename SolutionType>
783template<
typename ValueType,
typename SolutionType>
785 std::vector<SolutionType>& x,
786 std::vector<ValueType>
const& b)
const {
788 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"We did not implement interval iteration for interval-based models");
792 helper::IntervalIterationHelper<ValueType, false> iiHelper(viOperatorNontriv);
794 auto lowerBoundsCallback = [&](std::vector<SolutionType>& vector) { this->createLowerBoundsVector(vector); };
795 auto upperBoundsCallback = [&](std::vector<SolutionType>& vector) { this->createUpperBoundsVector(vector); };
797 uint64_t numIterations{0};
799 this->showProgressIterative(numIterations);
800 bool terminateEarly = this->hasCustomTerminationCondition() && this->getTerminationCondition().terminateNow(data.x,
SolverGuarantee::LessOrEqual) &&
804 std::optional<storm::storage::BitVector> optionalRelevantValues;
805 if (this->hasRelevantValues()) {
806 optionalRelevantValues = this->getRelevantValues();
808 this->startMeasureProgress();
810 dir, iiCallback, optionalRelevantValues);
811 this->reportStatus(status, numIterations);
814 if (this->isTrackSchedulerSet()) {
815 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
818 if (!this->isCachingEnabled()) {
826template<
typename ValueType,
typename SolutionType>
827bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsSoundValueIteration(Environment
const& env,
OptimizationDirection dir,
828 std::vector<SolutionType>& x,
829 std::vector<ValueType>
const& b)
const {
831 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"SoundVI does not handle interval-based models");
835 assert(x.size() == this->A->getRowGroupCount());
837 std::optional<ValueType> lowerBound, upperBound;
838 if (this->hasLowerBound()) {
839 lowerBound = this->getLowerBound(
true);
841 if (this->hasUpperBound()) {
842 upperBound = this->getUpperBound(
true);
848 uint64_t numIterations{0};
850 this->showProgressIterative(numIterations);
851 return this->updateStatus(current.status,
852 this->hasCustomTerminationCondition() && current.checkCustomTerminationCondition(this->getTerminationCondition()),
853 numIterations, env.solver().minMax().getMaximalNumberOfIterations());
855 this->startMeasureProgress();
857 std::optional<storm::storage::BitVector> optionalRelevantValues;
858 if (this->hasRelevantValues()) {
859 optionalRelevantValues = this->getRelevantValues();
861 auto status = sviHelper.SVI(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(), precision, dir, lowerBound, upperBound,
862 sviCallback, optionalRelevantValues);
865 if (this->isTrackSchedulerSet()) {
866 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
869 this->reportStatus(status, numIterations);
871 if (!this->isCachingEnabled()) {
879template<
typename ValueType,
typename SolutionType>
880bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsViToPi(Environment
const& env,
OptimizationDirection dir,
881 std::vector<SolutionType>& x, std::vector<ValueType>
const& b)
const {
883 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"ViToPi does not handle interval-based models");
887 std::vector<storm::storage::sparse::state_type> initialSched;
889 Environment viEnv = env;
890 viEnv.solver().minMax().setMethod(MinMaxMethod::ValueIteration);
891 viEnv.solver().setForceExact(
false);
892 viEnv.solver().setForceSoundness(
false);
894 impreciseSolver->setHasUniqueSolution(this->hasUniqueSolution());
895 impreciseSolver->setTrackScheduler(
true);
896 if (this->hasInitialScheduler()) {
897 auto initSched = this->getInitialScheduler();
898 impreciseSolver->setInitialScheduler(std::move(initSched));
900 auto impreciseSolverReq = impreciseSolver->getRequirements(viEnv, dir);
901 STORM_LOG_THROW(!impreciseSolverReq.hasEnabledCriticalRequirement(), storm::exceptions::UnmetRequirementException,
902 "The value-iteration based solver has an unmet requirement: " << impreciseSolverReq.getEnabledRequirementsAsString());
903 impreciseSolver->setRequirementsChecked(
true);
906 impreciseSolver->solveEquations(viEnv, dir, xVi, bVi);
907 initialSched = impreciseSolver->getSchedulerChoices();
909 STORM_LOG_INFO(
"Found initial policy using Value Iteration. Starting Policy iteration now.");
910 return performPolicyIteration(env, dir, x, b, std::move(initialSched));
913template<
typename ValueType,
typename SolutionType>
914bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsRationalSearch(Environment
const& env,
OptimizationDirection dir,
915 std::vector<SolutionType>& x,
916 std::vector<ValueType>
const& b)
const {
918 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Rational search does not handle interval-based models");
923 std::shared_ptr<helper::ValueIterationOperator<storm::RationalNumber, false>> exactOp;
924 std::shared_ptr<helper::ValueIterationOperator<double, false>> impreciseOp;
925 std::function<bool(uint64_t, uint64_t)> fixedChoicesCallback;
926 if (this->choiceFixedForRowGroup) {
928 assert(this->initialScheduler);
929 fixedChoicesCallback = [&](uint64_t groupIndex, uint64_t localRowIndex) {
930 return this->choiceFixedForRowGroup->get(groupIndex) && this->initialScheduler->at(groupIndex) != localRowIndex;
934 if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
935 exactOp = viOperatorNontriv;
936 impreciseOp = std::make_shared<helper::ValueIterationOperator<double, false>>();
937 impreciseOp->setMatrixBackwards(this->A->template toValueType<double>(), &this->A->getRowGroupIndices());
938 if (this->choiceFixedForRowGroup) {
939 impreciseOp->setIgnoredRows(
true, fixedChoicesCallback);
941 }
else if constexpr (std::is_same_v<ValueType, double>) {
942 impreciseOp = viOperatorNontriv;
943 exactOp = std::make_shared<helper::ValueIterationOperator<storm::RationalNumber, false>>();
944 exactOp->setMatrixBackwards(this->A->template toValueType<storm::RationalNumber>(), &this->A->getRowGroupIndices());
945 if (this->choiceFixedForRowGroup) {
946 exactOp->setIgnoredRows(
true, fixedChoicesCallback);
950 storm::solver::helper::RationalSearchHelper<ValueType, storm::RationalNumber, double, false> rsHelper(exactOp, impreciseOp);
951 uint64_t numIterations{0};
953 this->showProgressIterative(numIterations);
954 return this->updateStatus(current, x,
SolverGuarantee::None, numIterations, env.solver().minMax().getMaximalNumberOfIterations());
956 this->startMeasureProgress();
959 this->reportStatus(status, numIterations);
962 if (this->isTrackSchedulerSet()) {
963 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
966 if (!this->isCachingEnabled()) {
974template<
typename ValueType,
typename SolutionType>
976 auxiliaryRowGroupVector.reset();
977 if (viOperatorTriv) {
978 viOperatorTriv.reset();
980 if (viOperatorNontriv) {
981 viOperatorNontriv.reset();
SolverEnvironment & solver()
uint64_t const & getMaximalNumberOfIterations() const
storm::RationalNumber const & getPrecision() const
bool const & isMethodSetFromDefault() const
storm::solver::MinMaxMethod const & getMethod() const
bool isForceRequireUnique() const
bool const & getRelativeTerminationCriterion() const
std::optional< storm::RationalNumber > const & getUpperBoundGuessingFactor() const
OviSolverEnvironment const & ovi() const
MinMaxSolverEnvironment & minMax()
bool isForceExact() const
bool isForceSoundness() const
virtual std::unique_ptr< MinMaxLinearEquationSolver< ValueType, SolutionType > > create(Environment const &env) const override
virtual void clearCache() const override
Clears the currently cached data that has been stored during previous calls of the solver.
IterativeMinMaxLinearEquationSolver(std::unique_ptr< LinearEquationSolverFactory< SolutionType > > &&linearEquationSolverFactory)
virtual bool internalSolveEquations(Environment const &env, OptimizationDirection dir, std::vector< SolutionType > &x, std::vector< ValueType > const &b) const override
virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const &env, boost::optional< storm::solver::OptimizationDirection > const &direction=boost::none, bool const &hasInitialScheduler=false) const override
Retrieves the requirements of this solver for solving equations with the current settings.
An interface that represents an abstract linear equation solver.
virtual void clearCache() const
OptimizationDirectionSetting direction
bool hasUniqueSolution() const
bool hasNoEndComponents() const
bool hasInitialScheduler() const
MinMaxLinearEquationSolverRequirements & requireBounds(bool critical=true)
MinMaxLinearEquationSolverRequirements & requireUniqueSolution(bool critical=true)
MinMaxLinearEquationSolverRequirements & requireLowerBounds(bool critical=true)
MinMaxLinearEquationSolverRequirements & requireValidInitialScheduler(bool critical=true)
MinMaxLinearEquationSolverRequirements & requireUpperBounds(bool critical=true)
StandardMinMaxLinearEquationSolver()
storm::storage::SparseMatrix< ValueType > const * A
Implements Optimistic value iteration.
Implements sound value iteration.
A bit vector that is internally represented as a vector of 64-bit values.
A class that holds a possibly non-square matrix in the compressed row storage format.
void convertToEquationSystem()
Transforms the matrix into an equation system.
SparseMatrix selectRowsFromRowGroups(std::vector< index_type > const &rowGroupToRowIndexMapping, bool insertDiagonalEntries=true) const
Selects exactly one row from each row group of this matrix and returns the resulting matrix.
#define STORM_LOG_INFO(message)
#define STORM_LOG_WARN(message)
#define STORM_LOG_ERROR(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
SFTBDDChecker::ValueType ValueType
bool constexpr maximize(OptimizationDirection d)
void preserveOldRelevantValues(std::vector< ValueType > const &allValues, storm::storage::BitVector const &relevantValues, std::vector< ValueType > &oldValues)
std::string toString(GurobiSolverMethod const &method)
Yields a string representation of the GurobiSolverMethod.
ValueType computeMaxAbsDiff(std::vector< ValueType > const &allValues, storm::storage::BitVector const &relevantValues, std::vector< ValueType > const &oldValues)
UncertaintyResolutionMode
std::vector< TargetType > convertNumericVector(std::vector< SourceType > const &oldVector)
Converts the given vector to the given ValueType Assumes that both, TargetType and SourceType are num...
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 hasNonZeroEntry(std::vector< T > const &v)
ValueType max(ValueType const &first, ValueType const &second)
ValueType min(ValueType const &first, ValueType const &second)
bool isZero(ValueType const &a)
ValueType abs(ValueType const &number)
TargetType convertNumber(SourceType const &number)
solver::OptimizationDirection OptimizationDirection
constexpr bool IsIntervalType
Helper to check if a type is an interval.
static const bool IsExact