34template<
typename ValueType,
typename SolutionType>
37 : linearEquationSolverFactory(
std::move(linearEquationSolverFactory)) {
41template<
typename ValueType,
typename SolutionType>
48template<
typename ValueType,
typename SolutionType>
55template<
typename ValueType,
typename SolutionType>
56MinMaxMethod IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::getMethod(
Environment const& env,
bool isExactMode)
const {
60 if (isExactMode && method != MinMaxMethod::PolicyIteration && method != MinMaxMethod::RationalSearch && method != MinMaxMethod::ViToPi) {
63 "Selecting 'Policy iteration' as the solution technique to guarantee exact results. If you want to override this, please explicitly specify a "
65 method = MinMaxMethod::PolicyIteration;
67 STORM_LOG_WARN(
"The selected solution method " <<
toString(method) <<
" does not guarantee exact results.");
69 }
else if (env.
solver().
isForceSoundness() && method != MinMaxMethod::SoundValueIteration && method != MinMaxMethod::IntervalIteration &&
70 method != MinMaxMethod::PolicyIteration && method != MinMaxMethod::RationalSearch && method != MinMaxMethod::OptimisticValueIteration &&
71 method != MinMaxMethod::GuessingValueIteration) {
73 method = MinMaxMethod::OptimisticValueIteration;
77 <<
"' as the solution technique to guarantee sound results. If you want to override this, please explicitly specify a different method.");
79 STORM_LOG_WARN(
"The selected solution method does not guarantee sound results.");
85 STORM_LOG_WARN(
"Selected method is not supported for this solver and interval models, switching to robust value iteration.");
86 method = MinMaxMethod::ValueIteration;
89 STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch ||
90 method == MinMaxMethod::SoundValueIteration || method == MinMaxMethod::IntervalIteration ||
91 method == MinMaxMethod::OptimisticValueIteration || method == MinMaxMethod::GuessingValueIteration || method == MinMaxMethod::ViToPi,
92 storm::exceptions::InvalidEnvironmentException,
"This solver does not support the selected method '" <<
toString(method) <<
"'.");
96template<
typename ValueType,
typename SolutionType>
98 std::vector<SolutionType>& x, std::vector<ValueType>
const& b)
const {
101 case MinMaxMethod::ValueIteration:
102 result = solveEquationsValueIteration(env, dir, x, b);
104 case MinMaxMethod::OptimisticValueIteration:
105 result = solveEquationsOptimisticValueIteration(env, dir, x, b);
107 case MinMaxMethod::GuessingValueIteration:
108 result = solveEquationsGuessingValueIteration(env, dir, x, b);
110 case MinMaxMethod::PolicyIteration:
111 result = solveEquationsPolicyIteration(env, dir, x, b);
113 case MinMaxMethod::RationalSearch:
114 result = solveEquationsRationalSearch(env, dir, x, b);
116 case MinMaxMethod::IntervalIteration:
117 result = solveEquationsIntervalIteration(env, dir, x, b);
119 case MinMaxMethod::SoundValueIteration:
120 result = solveEquationsSoundValueIteration(env, dir, x, b);
122 case MinMaxMethod::ViToPi:
123 result = solveEquationsViToPi(env, dir, x, b);
126 STORM_LOG_THROW(
false, storm::exceptions::InvalidEnvironmentException,
"This solver does not implement the selected solution method.");
132template<
typename ValueType,
typename SolutionType>
133void IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::setUpViOperator()
const {
134 if (!viOperatorTriv && !viOperatorNontriv) {
135 if (this->A->hasTrivialRowGrouping()) {
137 viOperatorTriv = std::make_shared<helper::ValueIterationOperator<ValueType, true, SolutionType>>();
138 viOperatorTriv->setMatrixBackwards(*this->A);
144 viOperatorNontriv = std::make_shared<helper::ValueIterationOperator<ValueType, false, SolutionType>>();
145 viOperatorNontriv->setMatrixBackwards(*this->A);
149 viOperatorNontriv = std::make_shared<helper::ValueIterationOperator<ValueType, false, SolutionType>>();
150 viOperatorNontriv->setMatrixBackwards(*this->A);
153 if (this->choiceFixedForRowGroup) {
156 auto callback = [&](uint64_t groupIndex, uint64_t localRowIndex) {
157 return this->choiceFixedForRowGroup->get(groupIndex) && this->initialScheduler->at(groupIndex) != localRowIndex;
159 if (viOperatorTriv) {
160 viOperatorTriv->setIgnoredRows(
true, callback);
162 if (viOperatorNontriv) {
163 viOperatorNontriv->setIgnoredRows(
true, callback);
168template<
typename ValueType,
typename SolutionType>
169void IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::extractScheduler(std::vector<SolutionType>& x, std::vector<ValueType>
const& b,
174 if (!this->robustSchedulerIndex) {
175 this->robustSchedulerIndex = std::vector<uint64_t>(x.size(), 0);
177 this->robustSchedulerIndex->resize(x.size(), 0);
179 uint64_t numSchedulerChoices = 0;
180 for (uint64_t row = 0; row < this->A->getRowCount(); ++row) {
181 this->robustSchedulerIndex->at(row) = numSchedulerChoices;
182 numSchedulerChoices += this->A->getRow(row).getNumberOfEntries();
185 if (!this->schedulerChoices) {
186 this->schedulerChoices = std::vector<uint64_t>(numSchedulerChoices, 0);
188 this->schedulerChoices->resize(numSchedulerChoices, 0);
192 if (!this->schedulerChoices) {
193 this->schedulerChoices = std::vector<uint64_t>(x.size(), 0);
195 this->schedulerChoices->resize(x.size(), 0);
200 if (!viOperatorTriv && !viOperatorNontriv) {
201 STORM_LOG_WARN(
"Expected VI operator to be initialized for scheduler extraction. Initializing now, but this is inefficient.");
204 if (viOperatorTriv) {
206 storm::solver::helper::SchedulerTrackingHelper<ValueType, SolutionType, true> schedHelper(viOperatorTriv);
207 schedHelper.computeScheduler(x, b, dir, *this->schedulerChoices, uncertaintyResolutionMode, updateX ? &x :
nullptr, this->robustSchedulerIndex);
209 STORM_LOG_ERROR(
"SchedulerTrackingHelper not implemented for this setting (trivial row grouping but not Interval->double).");
212 if (viOperatorNontriv) {
213 storm::solver::helper::SchedulerTrackingHelper<ValueType, SolutionType, false> schedHelper(viOperatorNontriv);
214 schedHelper.computeScheduler(x, b, dir, *this->schedulerChoices, uncertaintyResolutionMode, updateX ? &x :
nullptr, this->robustSchedulerIndex);
218template<
typename ValueType,
typename SolutionType>
219bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveInducedEquationSystem(
221 std::vector<SolutionType>& x, std::vector<ValueType>& subB, std::vector<ValueType>
const& originalB,
OptimizationDirection dir)
const {
225 "We did not implement solving induced equation systems for interval-based models outside of robust VI.");
229 STORM_LOG_ASSERT(subB.size() == x.size(),
"Sizes of subB and x do not coincide.");
230 STORM_LOG_ASSERT(this->linearEquationSolverFactory !=
nullptr,
"Wrong constructor was called.");
232 storm::exceptions::NotImplementedException,
"Solving induced system of Interval Model not supported for the selected equation solver.");
234 storm::storage::SparseMatrixBuilder<SolutionType> newMatrixBuilder(this->A->getRowCount(), this->A->getColumnCount(), this->A->getEntryCount());
237 auto schedulerIterator = scheduler.begin();
238 for (uint64_t rowIndex = 0; rowIndex < this->A->getRowCount(); rowIndex++) {
239 auto const& row = this->A->getRow(rowIndex);
241 static std::vector<SolutionType> tmp;
246 for (
auto const& entry : row) {
247 tmp.push_back(entry.getValue().lower());
248 probLeft -= entry.getValue().lower();
251 auto const& rowIter = row.begin();
252 for (uint64_t i = 0;
i < row.getNumberOfEntries();
i++, schedulerIterator++) {
254 auto const& entry = rowIter[*schedulerIterator];
255 SolutionType
const diameter = entry.getValue().upper() - entry.getValue().lower();
257 tmp[*schedulerIterator] += value;
264 for (uint64_t i = 0;
i < row.getNumberOfEntries();
i++) {
265 auto const& entry = rowIter[
i];
266 newMatrixBuilder.addNextValue(rowIndex, entry.getColumn(), tmp[i]);
269 STORM_LOG_ASSERT(schedulerIterator == scheduler.end(),
"Offset issue in scheduler?");
273 std::vector<SolutionType> b;
274 for (
auto const& entry : subB) {
275 if (dir == OptimizationDirection::Maximize) {
276 b.push_back(entry.upper());
278 b.push_back(entry.lower());
282 auto const submatrix = newMatrixBuilder.build();
285 if (!linearEquationSolver) {
287 linearEquationSolver = this->linearEquationSolverFactory->create(env, std::move(submatrix));
288 linearEquationSolver->setBoundsFromOtherSolver(*
this);
289 linearEquationSolver->setCachingEnabled(
true);
292 linearEquationSolver->setMatrix(std::move(submatrix));
295 return linearEquationSolver->solveEquations(env, x, b);
297 STORM_LOG_ASSERT(subB.size() == x.size(),
"Sizes of subB and x do not coincide.");
298 STORM_LOG_ASSERT(this->linearEquationSolverFactory !=
nullptr,
"Wrong constructor was called.");
302 storm::storage::SparseMatrix<ValueType> submatrix;
305 if (convertToEquationSystem) {
311 if (!linearEquationSolver) {
313 linearEquationSolver = this->linearEquationSolverFactory->create(env, std::move(submatrix));
314 linearEquationSolver->setBoundsFromOtherSolver(*
this);
315 linearEquationSolver->setCachingEnabled(
true);
318 linearEquationSolver->setMatrix(std::move(submatrix));
321 return linearEquationSolver->solveEquations(env, x, subB);
325template<
typename ValueType,
typename SolutionType>
326bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsPolicyIteration(Environment
const& env,
OptimizationDirection dir,
327 std::vector<SolutionType>& x,
328 std::vector<ValueType>
const& b)
const {
329 std::vector<storm::storage::sparse::state_type> scheduler =
330 this->hasInitialScheduler() ? this->getInitialScheduler() : std::vector<storm::storage::sparse::
state_type>(this->A->getRowGroupCount());
331 return performPolicyIteration(env, dir, x, b, std::move(scheduler));
334template<
typename ValueType,
typename SolutionType>
335bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::performPolicyIteration(
336 Environment
const& env,
OptimizationDirection dir, std::vector<SolutionType>& x, std::vector<ValueType>
const& b,
337 std::vector<storm::storage::sparse::state_type>&& initialPolicy)
const {
339 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"We did not implement policy iteration for interval-based models.");
342 std::vector<storm::storage::sparse::state_type> scheduler = std::move(initialPolicy);
344 if (!auxiliaryRowGroupVector) {
345 auxiliaryRowGroupVector = std::make_unique<std::vector<ValueType>>(this->A->getRowGroupCount());
347 std::vector<ValueType>& subB = *auxiliaryRowGroupVector;
350 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver;
352 std::unique_ptr<storm::Environment> environmentOfSolverStorage;
353 auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType());
355 bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision();
356 bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion();
357 if (changePrecision || changeRelative) {
358 environmentOfSolverStorage = std::make_unique<storm::Environment>(env);
359 boost::optional<storm::RationalNumber> newPrecision;
360 boost::optional<bool> newRelative;
361 if (changePrecision) {
362 newPrecision = env.solver().minMax().getPrecision();
364 if (changeRelative) {
367 environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative);
370 storm::Environment
const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env;
373 uint64_t iterations = 0;
374 this->startMeasureProgress();
377 solveInducedEquationSystem(environmentOfSolver, solver, scheduler, x, subB, b, dir);
380 bool schedulerImproved =
false;
382 for (uint_fast64_t group = 0; group < this->A->getRowGroupCount(); ++group) {
383 if (!this->choiceFixedForRowGroup || !this->choiceFixedForRowGroup.get()[group]) {
385 uint_fast64_t currentChoice = scheduler[group];
386 for (uint_fast64_t choice = this->A->getRowGroupIndices()[group]; choice < this->A->getRowGroupIndices()[group + 1]; ++choice) {
388 if (choice - this->A->getRowGroupIndices()[group] == currentChoice) {
394 for (
auto const& entry : this->A->getRow(choice)) {
395 choiceValue += entry.getValue() * x[entry.getColumn()];
397 choiceValue += b[choice];
402 if (valueImproved(dir, x[group], choiceValue)) {
403 schedulerImproved =
true;
404 scheduler[group] = choice - this->A->getRowGroupIndices()[group];
405 x[group] = std::move(choiceValue);
412 if (!schedulerImproved) {
420 iterations, env.solver().minMax().getMaximalNumberOfIterations());
423 this->showProgressIterative(iterations);
432 this->setSolutionBounds(solver->getSolutionBounds());
435 this->reportStatus(status, iterations);
438 if (this->isTrackSchedulerSet()) {
439 this->schedulerChoices = std::move(scheduler);
442 if (!this->isCachingEnabled()) {
450template<
typename ValueType,
typename SolutionType>
451bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::valueImproved(
OptimizationDirection dir, ValueType
const& value1,
452 ValueType
const& value2)
const {
453 if (dir == OptimizationDirection::Minimize) {
454 return value2 < value1;
456 return value2 > value1;
460template<
typename ValueType,
typename SolutionType>
466 bool needsLinEqSolver =
false;
467 needsLinEqSolver |= method == MinMaxMethod::PolicyIteration;
468 needsLinEqSolver |= method == MinMaxMethod::ValueIteration && (this->hasInitialScheduler() ||
hasInitialScheduler);
469 needsLinEqSolver |= method == MinMaxMethod::ViToPi;
473 STORM_LOG_ASSERT(!needsLinEqSolver,
"Intervals should not require a linear equation solver.");
475 }
else if (needsLinEqSolver) {
481 if (method == MinMaxMethod::ValueIteration) {
496 }
else if (method == MinMaxMethod::OptimisticValueIteration) {
503 }
else if (method == MinMaxMethod::GuessingValueIteration) {
509 }
else if (method == MinMaxMethod::IntervalIteration) {
515 }
else if (method == MinMaxMethod::RationalSearch) {
524 }
else if (method == MinMaxMethod::PolicyIteration) {
532 }
else if (method == MinMaxMethod::SoundValueIteration) {
537 }
else if (method == MinMaxMethod::ViToPi) {
543 STORM_LOG_THROW(
false, storm::exceptions::InvalidEnvironmentException,
"Unsupported technique for iterative MinMax linear equation solver.");
548template<
typename ValueType,
typename SolutionType>
551 auto oldValueIt = oldValues.begin();
552 for (uint64_t value : relevantValues) {
559template<
typename ValueType,
typename SolutionType>
560ValueType
computeMaxAbsDiff(std::vector<ValueType>
const& allOldValues, std::vector<ValueType>
const& allNewValues,
563 for (uint64_t value : relevantValues) {
569template<
typename ValueType,
typename SolutionType>
571 std::vector<SolutionType>& x,
572 std::vector<ValueType>
const& b)
const {
574 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"We did not implement optimistic value iteration for interval-based models.");
580 if (this->isTrackSchedulerSet()) {
581 this->schedulerChoices = std::vector<uint_fast64_t>(x.size(), 0);
583 this->setSolutionBoundsExact(x);
591 std::optional<ValueType> lowerBound, upperBound;
592 if (this->hasLowerBound()) {
593 lowerBound = this->getLowerBound(
true);
595 if (this->hasUpperBound()) {
596 upperBound = this->getUpperBound(
true);
598 uint64_t numIterations{0};
599 auto oviCallback = [&](
SolverStatus const& current, std::vector<ValueType>
const& v) {
600 this->showProgressIterative(numIterations);
603 this->createLowerBoundsVector(x);
604 std::optional<ValueType> guessingFactor;
608 this->startMeasureProgress();
609 storm::solver::SolutionBounds<ValueType> solutionBounds;
611 upperBound, oviCallback, solutionBounds);
612 if (solutionBounds.
hasAny()) {
613 this->setSolutionBounds(std::move(solutionBounds));
615 this->reportStatus(status, numIterations);
618 if (this->isTrackSchedulerSet()) {
619 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
622 if (!this->isCachingEnabled()) {
630template<
typename ValueType,
typename SolutionType>
631bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsGuessingValueIteration(Environment
const& env,
OptimizationDirection dir,
632 std::vector<SolutionType>& x,
633 std::vector<ValueType>
const& b)
const {
635 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"We did not implement guessing value iteration for interval-based models.");
641 auto upperX = std::make_unique<std::vector<SolutionType>>(x.size());
643 storm::solver::helper::GuessingValueIterationHelper<ValueType, false>
helper(viOperatorNontriv, *this->A);
645 uint64_t numIterations{0};
648 this->showProgressIterative(numIterations);
649 bool terminateEarly =
652 return this->updateStatus(data.status, terminateEarly, numIterations, env.solver().minMax().getMaximalNumberOfIterations());
655 this->createLowerBoundsVector(lowerX);
656 this->createUpperBoundsVector(*upperX);
658 this->startMeasureProgress();
659 auto statusIters =
helper.solveEquations(lowerX, *upperX, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(),
662 storm::solver::SolutionBounds<SolutionType> solutionBounds;
663 solutionBounds.
lower = lowerX;
664 solutionBounds.
upper = *upperX;
665 this->setSolutionBounds(std::move(solutionBounds));
669 lowerX, *upperX, x, [&two](ValueType
const& first, ValueType
const& second) -> ValueType {
return (first + second) / two; });
671 this->reportStatus(statusIters, numIterations);
674 if (this->isTrackSchedulerSet()) {
675 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
678 if (!this->isCachingEnabled()) {
686template<
typename ValueType,
typename SolutionType>
687bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsValueIteration(Environment
const& env,
OptimizationDirection dir,
688 std::vector<SolutionType>& x,
689 std::vector<ValueType>
const& b)
const {
696 if (this->hasInitialScheduler()) {
697 if (!auxiliaryRowGroupVector) {
698 auxiliaryRowGroupVector = std::make_unique<std::vector<ValueType>>(this->A->getRowGroupCount());
701 std::unique_ptr<storm::solver::LinearEquationSolver<SolutionType>> linEqSolver;
703 std::unique_ptr<storm::Environment> environmentOfSolverStorage;
704 auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType());
706 bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision();
707 bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion();
708 if (changePrecision || changeRelative) {
709 environmentOfSolverStorage = std::make_unique<storm::Environment>(env);
710 boost::optional<storm::RationalNumber> newPrecision;
711 boost::optional<bool> newRelative;
712 if (changePrecision) {
713 newPrecision = env.solver().minMax().getPrecision();
715 if (changeRelative) {
718 environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative);
721 storm::Environment
const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env;
723 bool success = solveInducedEquationSystem(environmentOfSolver, linEqSolver, this->getInitialScheduler(), x, *auxiliaryRowGroupVector, b, dir);
730 if (linEqSolver->hasExactSolutionBounds()) {
731 boundGuarantee = guarantee;
736 }
else if (!this->hasUniqueSolution()) {
738 this->createLowerBoundsVector(x);
741 this->createUpperBoundsVector(x);
744 boundGuarantee = guarantee;
745 }
else if (this->hasCustomTerminationCondition()) {
747 this->createLowerBoundsVector(x);
750 this->createUpperBoundsVector(x);
753 boundGuarantee = guarantee;
756 uint64_t numIterations{0};
758 this->showProgressIterative(numIterations);
759 return this->updateStatus(current, x, guarantee, numIterations, env.solver().minMax().getMaximalNumberOfIterations());
761 this->startMeasureProgress();
765 storm::solver::SolutionBounds<SolutionType> solutionBounds;
767 if (boundGuarantee !=
SolverGuarantee::None || (this->hasUniqueSolution() && env.solver().isForceSoundness())) {
768 solutionBoundsRef.
reset(solutionBounds);
771 if (this->A->hasTrivialRowGrouping()) {
772 storm::solver::helper::ValueIterationHelper<ValueType, true, SolutionType> viHelper(viOperatorTriv);
774 auto status = viHelper.VI(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(),
776 env.solver().minMax().getMultiplicationStyle(), this->getUncertaintyResolutionMode(), solutionBoundsRef, boundGuarantee);
777 this->reportStatus(status, numIterations);
779 if (solutionBounds.
hasAny()) {
780 this->setSolutionBounds(std::move(solutionBounds));
784 if (this->isTrackSchedulerSet()) {
785 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
788 if (!this->isCachingEnabled()) {
794 storm::solver::helper::ValueIterationHelper<ValueType, false, SolutionType> viHelper(viOperatorNontriv);
796 auto status = viHelper.VI(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(),
798 env.solver().minMax().getMultiplicationStyle(), this->getUncertaintyResolutionMode(), solutionBoundsRef, boundGuarantee);
799 this->reportStatus(status, numIterations);
801 if (solutionBounds.
hasAny()) {
802 this->setSolutionBounds(std::move(solutionBounds));
806 if (this->isTrackSchedulerSet()) {
807 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
810 if (!this->isCachingEnabled()) {
818template<
typename ValueType,
typename SolutionType>
829template<
typename ValueType,
typename SolutionType>
831 std::vector<SolutionType>& x,
832 std::vector<ValueType>
const& b)
const {
834 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"We did not implement interval iteration for interval-based models.");
838 helper::IntervalIterationHelper<ValueType, false> iiHelper(viOperatorNontriv);
840 auto lowerBoundsCallback = [&](std::vector<SolutionType>& vector) { this->createLowerBoundsVector(vector); };
841 auto upperBoundsCallback = [&](std::vector<SolutionType>& vector) { this->createUpperBoundsVector(vector); };
843 uint64_t numIterations{0};
845 this->showProgressIterative(numIterations);
846 bool terminateEarly =
851 std::optional<storm::storage::BitVector> optionalRelevantValues;
852 if (this->hasRelevantValues()) {
853 optionalRelevantValues = this->getRelevantValues();
855 this->startMeasureProgress();
856 storm::solver::SolutionBounds<ValueType> solutionBounds;
858 dir, iiCallback, optionalRelevantValues, solutionBounds);
859 if (solutionBounds.
hasAny()) {
860 this->setSolutionBounds(std::move(solutionBounds));
862 this->reportStatus(status, numIterations);
865 if (this->isTrackSchedulerSet()) {
866 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
869 if (!this->isCachingEnabled()) {
877template<
typename ValueType,
typename SolutionType>
878bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsSoundValueIteration(Environment
const& env,
OptimizationDirection dir,
879 std::vector<SolutionType>& x,
880 std::vector<ValueType>
const& b)
const {
882 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"SoundVI does not handle interval-based models.");
886 STORM_LOG_ASSERT(x.size() == this->A->getRowGroupCount(),
"Solution vector size mismatch.");
888 std::optional<ValueType> lowerBound, upperBound;
889 if (this->hasLowerBound()) {
890 lowerBound = this->getLowerBound(
true);
892 if (this->hasUpperBound()) {
893 upperBound = this->getUpperBound(
true);
899 uint64_t numIterations{0};
901 this->showProgressIterative(numIterations);
902 return this->updateStatus(current.status,
903 this->hasCustomTerminationCondition() && current.checkCustomTerminationCondition(this->getTerminationCondition()),
904 numIterations, env.solver().minMax().getMaximalNumberOfIterations());
906 this->startMeasureProgress();
908 std::optional<storm::storage::BitVector> optionalRelevantValues;
909 if (this->hasRelevantValues()) {
910 optionalRelevantValues = this->getRelevantValues();
912 storm::solver::SolutionBounds<ValueType> solutionBounds;
913 auto status = sviHelper.SVI(x, b, numIterations, env.solver().minMax().getRelativeTerminationCriterion(), precision, dir, lowerBound, upperBound,
914 sviCallback, optionalRelevantValues, solutionBounds);
915 if (solutionBounds.
hasAny()) {
916 this->setSolutionBounds(std::move(solutionBounds));
920 if (this->isTrackSchedulerSet()) {
921 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
924 this->reportStatus(status, numIterations);
926 if (!this->isCachingEnabled()) {
934template<
typename ValueType,
typename SolutionType>
935bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsViToPi(Environment
const& env,
OptimizationDirection dir,
936 std::vector<SolutionType>& x, std::vector<ValueType>
const& b)
const {
938 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"ViToPi does not handle interval-based models.");
942 std::vector<storm::storage::sparse::state_type> initialSched;
944 Environment viEnv = env;
945 viEnv.solver().minMax().setMethod(MinMaxMethod::ValueIteration);
946 viEnv.solver().setForceExact(
false);
947 viEnv.solver().setForceSoundness(
false);
949 impreciseSolver->setHasUniqueSolution(this->hasUniqueSolution());
950 impreciseSolver->setTrackScheduler(
true);
951 if (this->hasInitialScheduler()) {
952 auto initSched = this->getInitialScheduler();
953 impreciseSolver->setInitialScheduler(std::move(initSched));
955 auto impreciseSolverReq = impreciseSolver->getRequirements(viEnv, dir);
956 STORM_LOG_THROW(!impreciseSolverReq.hasEnabledCriticalRequirement(), storm::exceptions::UnmetRequirementException,
957 "The value-iteration based solver has an unmet requirement: " << impreciseSolverReq.getEnabledRequirementsAsString() <<
".");
958 impreciseSolver->setRequirementsChecked(
true);
961 impreciseSolver->solveEquations(viEnv, dir, xVi, bVi);
962 initialSched = impreciseSolver->getSchedulerChoices();
964 STORM_LOG_INFO(
"Found initial policy using Value Iteration. Starting Policy iteration now.");
965 return performPolicyIteration(env, dir, x, b, std::move(initialSched));
968template<
typename ValueType,
typename SolutionType>
969bool IterativeMinMaxLinearEquationSolver<ValueType, SolutionType>::solveEquationsRationalSearch(Environment
const& env,
OptimizationDirection dir,
970 std::vector<SolutionType>& x,
971 std::vector<ValueType>
const& b)
const {
973 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Rational search does not handle interval-based models.");
978 std::shared_ptr<helper::ValueIterationOperator<storm::RationalNumber, false>> exactOp;
979 std::shared_ptr<helper::ValueIterationOperator<double, false>> impreciseOp;
980 std::function<bool(uint64_t, uint64_t)> fixedChoicesCallback;
981 if (this->choiceFixedForRowGroup) {
984 fixedChoicesCallback = [&](uint64_t groupIndex, uint64_t localRowIndex) {
985 return this->choiceFixedForRowGroup->get(groupIndex) && this->initialScheduler->at(groupIndex) != localRowIndex;
989 if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
990 exactOp = viOperatorNontriv;
991 impreciseOp = std::make_shared<helper::ValueIterationOperator<double, false>>();
992 impreciseOp->setMatrixBackwards(this->A->template toValueType<double>(), &this->A->getRowGroupIndices());
993 if (this->choiceFixedForRowGroup) {
994 impreciseOp->setIgnoredRows(
true, fixedChoicesCallback);
996 }
else if constexpr (std::is_same_v<ValueType, double>) {
997 impreciseOp = viOperatorNontriv;
998 exactOp = std::make_shared<helper::ValueIterationOperator<storm::RationalNumber, false>>();
999 exactOp->setMatrixBackwards(this->A->template toValueType<storm::RationalNumber>(), &this->A->getRowGroupIndices());
1000 if (this->choiceFixedForRowGroup) {
1001 exactOp->setIgnoredRows(
true, fixedChoicesCallback);
1005 storm::solver::helper::RationalSearchHelper<ValueType, storm::RationalNumber, double, false> rsHelper(exactOp, impreciseOp);
1006 uint64_t numIterations{0};
1008 this->showProgressIterative(numIterations);
1009 return this->updateStatus(current, x,
SolverGuarantee::None, numIterations, env.solver().minMax().getMaximalNumberOfIterations());
1011 this->startMeasureProgress();
1016 this->setSolutionBoundsExact(x);
1019 this->reportStatus(status, numIterations);
1022 if (this->isTrackSchedulerSet()) {
1023 this->extractScheduler(x, b, dir, this->getUncertaintyResolutionMode());
1026 if (!this->isCachingEnabled()) {
1034template<
typename ValueType,
typename SolutionType>
1036 auxiliaryRowGroupVector.reset();
1037 if (viOperatorTriv) {
1038 viOperatorTriv.reset();
1040 if (viOperatorNontriv) {
1041 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
void reset()
Unsets the reference.
std::optional< storm::RationalNumber > const & getUpperBoundGuessingFactor() const
OviSolverEnvironment & ovi()
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.
OptionalRef(T &) -> OptionalRef< T >
deduction guides
static const bool IsExact
bool hasAny() const
Returns true if at least one of the bounds is set.
std::optional< std::vector< ValueType > > lower
std::optional< std::vector< ValueType > > upper