Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
ValueIterationHelper.cpp
Go to the documentation of this file.
2
8
9namespace storm::solver::helper {
10
11template<typename ValueType, storm::OptimizationDirection Dir, bool Relative, bool TrackDirection>
13 public:
14 VIOperatorBackend(ValueType const& precision) : precision{precision} {
15 // intentionally empty
16 }
17
19 isConverged = true;
20 if constexpr (TrackDirection) {
21 isNonDecreasing = true;
22 isNonIncreasing = true;
23 }
24 }
25
26 void firstRow(ValueType&& value, [[maybe_unused]] uint64_t rowGroup, [[maybe_unused]] uint64_t row) {
27 best = std::move(value);
28 }
29
30 void nextRow(ValueType&& value, [[maybe_unused]] uint64_t rowGroup, [[maybe_unused]] uint64_t row) {
31 best &= value;
32 }
33
34 void applyUpdate(ValueType& currValue, [[maybe_unused]] uint64_t rowGroup) {
35 if (isConverged) {
36 if constexpr (Relative) {
37 isConverged = storm::utility::abs<ValueType>(currValue - *best) <= storm::utility::abs<ValueType>(precision * currValue);
38 } else {
39 isConverged = storm::utility::abs<ValueType>(currValue - *best) <= precision;
40 }
41 }
42 if constexpr (TrackDirection) {
43 // Record the direction this iteration moves the operand in; see the comment in ValueIterationHelper::VI.
44 if (isNonDecreasing && *best < currValue) {
45 isNonDecreasing = false;
46 }
47 if (isNonIncreasing && currValue < *best) {
48 isNonIncreasing = false;
49 }
50 }
51 currValue = std::move(*best);
52 }
53
54 void endOfIteration() const {
55 // intentionally left empty.
56 }
57
58 bool converged() const {
59 return isConverged;
60 }
61
62 bool nonDecreasing() const {
63 return isNonDecreasing;
64 }
65
66 bool nonIncreasing() const {
67 return isNonIncreasing;
68 }
69
70 bool constexpr abort() const {
71 return false;
72 }
73
74 private:
76 ValueType const precision;
77 bool isConverged{true};
78 bool isNonDecreasing{true};
79 bool isNonIncreasing{true};
80};
81
82template<typename ValueType, bool TrivialRowGrouping, typename SolutionType>
88
89template<typename ValueType, bool TrivialRowGrouping, typename SolutionType>
90template<storm::OptimizationDirection Dir, bool Relative, storm::OptimizationDirection RobustDir, bool TrackDirection>
91SolverStatus ValueIterationHelper<ValueType, TrivialRowGrouping, SolutionType>::VI(std::vector<SolutionType>& operand, std::vector<ValueType> const& offsets,
92 uint64_t& numIterations, SolutionType const& precision,
93 std::function<SolverStatus(SolverStatus const&)> const& iterationCallback,
96 SolverGuarantee const& guarantee) const {
98 std::vector<SolutionType>* operand1{&operand};
99 std::vector<SolutionType>* operand2{&operand};
100 if (mult == MultiplicationStyle::Regular) {
101 operand2 = &viOperator->allocateAuxiliaryVector(operand.size());
102 }
103 bool resultInAuxVector{false};
105 while (status == SolverStatus::InProgress) {
106 ++numIterations;
107 bool applyResult = viOperator->template applyRobust<RobustDir>(*operand1, *operand2, offsets, backend);
108 if (applyResult) {
110 } else if (iterationCallback) {
111 status = iterationCallback(status);
112 }
113 if (mult == MultiplicationStyle::Regular) {
114 std::swap(operand1, operand2);
115 resultInAuxVector = !resultInAuxVector;
116 }
117 }
118 if (mult == MultiplicationStyle::Regular) {
119 if (resultInAuxVector) {
120 STORM_LOG_ASSERT(&operand == operand2, "Unexpected operand address.");
121 std::swap(*operand1, *operand2);
122 }
123 viOperator->freeAuxiliaryVector();
124 }
125 if (!solutionBounds.has_value()) {
126 return status;
127 }
128 if constexpr (TrackDirection) {
130 // An iteration that decreased nothing gives x <= T(x), so x lies below the unique fixpoint; dually for
131 // one that increased nothing.
132 if (backend.nonDecreasing()) {
133 solutionBounds->lower = operand;
134 }
135 if (backend.nonIncreasing()) {
136 solutionBounds->upper = operand;
137 }
138 }
139 } else if (guarantee == SolverGuarantee::LessOrEqual) {
140 // The iteration maintains a guarantee that held for the initial operand, so the result carries it too.
141 solutionBounds->lower = operand;
142 } else if (guarantee == SolverGuarantee::GreaterOrEqual) {
143 solutionBounds->upper = operand;
144 }
145 return status;
146}
147
148template<typename ValueType, bool TrivialRowGrouping, typename SolutionType>
149template<storm::OptimizationDirection Dir, bool Relative>
150SolverStatus ValueIterationHelper<ValueType, TrivialRowGrouping, SolutionType>::VI(std::vector<SolutionType>& operand, std::vector<ValueType> const& offsets,
151 uint64_t& numIterations, SolutionType const& precision,
152 const std::function<SolverStatus(const SolverStatus&)>& iterationCallback,
154 UncertaintyResolutionMode const& uncertaintyResolutionMode,
156 SolverGuarantee const& guarantee) const {
157 bool robustUncertainty = false;
158 if constexpr (storm::IsIntervalType<ValueType>) {
159 robustUncertainty = isUncertaintyResolvedRobust(uncertaintyResolutionMode, Dir);
160 }
161
162 // Reading the direction of every sweep costs in the innermost loop, so only do it where it is the sole route
163 // to a bound: where one is wanted and the operand carries no guarantee that the iteration already maintains.
164 bool const trackDirection = solutionBounds.has_value() && guarantee == SolverGuarantee::None;
165 if (robustUncertainty) {
166 if (trackDirection) {
167 return VI<Dir, Relative, invert(Dir), true>(operand, offsets, numIterations, precision, iterationCallback, mult, solutionBounds, guarantee);
168 }
169 return VI<Dir, Relative, invert(Dir), false>(operand, offsets, numIterations, precision, iterationCallback, mult, solutionBounds, guarantee);
170 } else {
171 if (trackDirection) {
172 return VI<Dir, Relative, Dir, true>(operand, offsets, numIterations, precision, iterationCallback, mult, solutionBounds, guarantee);
173 }
174 return VI<Dir, Relative, Dir, false>(operand, offsets, numIterations, precision, iterationCallback, mult, solutionBounds, guarantee);
175 }
176}
177
178template<typename ValueType, bool TrivialRowGrouping, typename SolutionType>
180 std::vector<SolutionType>& operand, std::vector<ValueType> const& offsets, uint64_t& numIterations, bool relative, SolutionType const& precision,
181 std::optional<storm::OptimizationDirection> const& dir, std::function<SolverStatus(SolverStatus const&)> const& iterationCallback, MultiplicationStyle mult,
182 UncertaintyResolutionMode const& uncertaintyResolutionMode, storm::OptionalRef<SolutionBounds<SolutionType>> solutionBounds,
183 SolverGuarantee const& guarantee) const {
184 if constexpr (storm::IsIntervalType<ValueType>) {
185 STORM_LOG_THROW(uncertaintyResolutionMode != UncertaintyResolutionMode::Unset, storm::exceptions::IllegalFunctionCallException,
186 "Uncertainty resolution mode must be set for uncertain (interval) models.");
187 STORM_LOG_THROW(dir.has_value() || (uncertaintyResolutionMode != UncertaintyResolutionMode::Robust &&
188 uncertaintyResolutionMode != UncertaintyResolutionMode::Cooperative),
189 storm::exceptions::IllegalFunctionCallException,
190 "Robust or cooperative nature resolution modes cannot be used if optimization direction is not set.");
191 }
192
193 STORM_LOG_ASSERT(TrivialRowGrouping || dir.has_value(), "No optimization direction given!");
194 if (!dir.has_value() || maximize(*dir)) {
195 if (relative) {
196 return VI<storm::OptimizationDirection::Maximize, true>(operand, offsets, numIterations, precision, iterationCallback, mult,
197 uncertaintyResolutionMode, solutionBounds, guarantee);
198 } else {
199 return VI<storm::OptimizationDirection::Maximize, false>(operand, offsets, numIterations, precision, iterationCallback, mult,
200 uncertaintyResolutionMode, solutionBounds, guarantee);
201 }
202 } else {
203 if (relative) {
204 return VI<storm::OptimizationDirection::Minimize, true>(operand, offsets, numIterations, precision, iterationCallback, mult,
205 uncertaintyResolutionMode, solutionBounds, guarantee);
206 } else {
207 return VI<storm::OptimizationDirection::Minimize, false>(operand, offsets, numIterations, precision, iterationCallback, mult,
208 uncertaintyResolutionMode, solutionBounds, guarantee);
209 }
210 }
211}
212
213template<typename ValueType, bool TrivialRowGrouping, typename SolutionType>
215 std::vector<SolutionType>& operand, std::vector<ValueType> const& offsets, bool relative, SolutionType const& precision,
216 std::optional<storm::OptimizationDirection> const& dir, std::function<SolverStatus(SolverStatus const&)> const& iterationCallback, MultiplicationStyle mult,
217 UncertaintyResolutionMode const& uncertaintyResolutionMode, storm::OptionalRef<SolutionBounds<SolutionType>> solutionBounds,
218 SolverGuarantee const& guarantee) const {
219 uint64_t numIterations = 0;
220 return VI(operand, offsets, numIterations, relative, precision, dir, iterationCallback, mult, uncertaintyResolutionMode, solutionBounds, guarantee);
221}
222
231
232} // namespace storm::solver::helper
Helper class that optionally holds a reference to an object of type T.
Definition OptionalRef.h:48
void firstRow(ValueType &&value, uint64_t rowGroup, uint64_t row)
void applyUpdate(ValueType &currValue, uint64_t rowGroup)
void nextRow(ValueType &&value, uint64_t rowGroup, uint64_t row)
ValueIterationHelper(std::shared_ptr< ValueIterationOperator< ValueType, TrivialRowGrouping, SolutionType > > viOperator)
SolverStatus VI(std::vector< SolutionType > &operand, std::vector< ValueType > const &offsets, uint64_t &numIterations, SolutionType const &precision, std::function< SolverStatus(SolverStatus const &)> const &iterationCallback={}, MultiplicationStyle mult=MultiplicationStyle::GaussSeidel, storm::OptionalRef< SolutionBounds< SolutionType > > solutionBounds=storm::NullRef, SolverGuarantee const &guarantee=SolverGuarantee::None) const
This class represents the Value Iteration Operator (also known as Bellman operator).
Stores and manages an extremal (maximal or minimal) value.
Definition Extremum.h:17
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
bool constexpr maximize(OptimizationDirection d)
bool isUncertaintyResolvedRobust(UncertaintyResolutionMode uncertaintyResolutionMode, OptimizationDirection optimizationDirection)
ValueType abs(ValueType const &number)
constexpr bool IsIntervalType
Helper to check if a type is an interval.
Sound lower and upper bounds on a solution vector.