Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
RationalSearchHelper.cpp
Go to the documentation of this file.
2
10
11namespace storm::solver::helper {
12
13template<typename TargetValueType, typename ExactValueType, typename ImpreciseValueType, bool TrivialRowGrouping>
16 std::shared_ptr<ValueIterationOperator<ImpreciseValueType, TrivialRowGrouping>> impreciseViOperator)
17 : exactOperator(exactViOperator), impreciseOperator(impreciseViOperator) {
18 // Intentionally left empty
19}
20
21template<typename ValueType, typename ExactValueType, storm::OptimizationDirection Dir>
22class RSBackend {
23 public:
25 allEqual = true;
26 }
27
28 void firstRow(ExactValueType&& value, [[maybe_unused]] uint64_t rowGroup, [[maybe_unused]] uint64_t row) {
29 best = std::move(value);
30 }
31
32 void nextRow(ExactValueType&& value, [[maybe_unused]] uint64_t rowGroup, [[maybe_unused]] uint64_t row) {
33 best &= value;
34 }
35
36 void applyUpdate(ExactValueType& currValue, [[maybe_unused]] uint64_t rowGroup) {
37 if (currValue != *best) {
38 allEqual = false;
39 }
40 }
41
42 void endOfIteration() const {
43 // intentionally left empty.
44 }
45
46 bool converged() const {
47 return allEqual;
48 }
49
50 bool constexpr abort() const {
51 return !allEqual;
52 }
53
54 private:
56 bool allEqual{true};
57};
58
59template<typename TargetValueType, typename ExactValueType, typename ImpreciseValueType, bool TrivialRowGrouping>
60template<typename ValueType, storm::OptimizationDirection Dir>
61RSResult RationalSearchHelper<TargetValueType, ExactValueType, ImpreciseValueType, TrivialRowGrouping>::sharpen(uint64_t precision,
62 std::vector<ValueType> const& operand,
63 std::vector<ExactValueType> const& exactOffsets,
64 std::vector<TargetValueType>& target) const {
65 RSBackend<ValueType, ExactValueType, Dir> backend;
66 auto& sharpOperand = exactOperator->allocateAuxiliaryVector(operand.size());
67
68 for (uint64_t p = 0; p <= precision; ++p) {
69 // If we need an exact computation but are currently using imprecise values, we might need to consider switching to precise values
70 if (std::is_same_v<ExactValueType, TargetValueType> && std::is_same_v<ValueType, ImpreciseValueType> &&
71 p > std::numeric_limits<ImpreciseValueType>::max_digits10) {
72 exactOperator->freeAuxiliaryVector();
74 }
75 storm::utility::kwek_mehlhorn::sharpen(p, operand, sharpOperand);
76
77 if (exactOperator->applyInPlace(sharpOperand, exactOffsets, backend)) {
78 // Put the solution into the target vector
79 if constexpr (std::is_same_v<ExactValueType, TargetValueType>) {
80 target.swap(sharpOperand);
81 } else {
82 target.resize(sharpOperand.size());
84 }
85 exactOperator->freeAuxiliaryVector();
87 }
88 }
89 exactOperator->freeAuxiliaryVector();
91}
92
93template<typename TargetValueType, typename ExactValueType, typename ImpreciseValueType, bool TrivialRowGrouping>
94template<typename ValueType>
95std::shared_ptr<ValueIterationOperator<ValueType, TrivialRowGrouping>> const&
97 if constexpr (std::is_same_v<ValueType, ExactValueType>) {
98 return exactOperator;
99 } else {
100 return impreciseOperator;
101 }
102}
103
104template<typename TargetValueType, typename ExactValueType, typename ImpreciseValueType, bool TrivialRowGrouping>
105template<typename ValueType, storm::OptimizationDirection Dir>
107 std::vector<ValueType>& operand, std::vector<ValueType> const& offsets, uint64_t& numIterations, ExactValueType precision,
108 std::vector<ExactValueType> const& exactOffsets, std::vector<TargetValueType>& target,
109 std::function<SolverStatus(SolverStatus const&)> const& iterationCallback) const {
110 ValueIterationHelper<ValueType, TrivialRowGrouping> viHelper(getOperator<ValueType>());
113 while (status == SolverStatus::InProgress) {
114 auto viStatus = viHelper.VI(operand, offsets, numIterations, false, storm::utility::convertNumber<ValueType>(precision), Dir, iterationCallback);
115
116 // Compute maximal precision until which to sharpen.
117 auto p = storm::utility::convertNumber<uint64_t>(
118 storm::utility::ceil(storm::utility::log10<ExactValueType>(storm::utility::one<ExactValueType>() / precision)));
119
120 // check if the sharpened vector is the desired solution.
121 result = sharpen<ValueType, Dir>(p, operand, exactOffsets, target);
122 switch (result) {
125 break;
127 if (viStatus != SolverStatus::Converged) {
128 status = viStatus;
129 } else {
130 // Increase the precision.
131 precision /= storm::utility::convertNumber<ExactValueType>(static_cast<uint64_t>(10));
132 }
133 break;
135 status = SolverStatus::Aborted;
136 break;
137 }
138 }
139 return std::pair(result, status);
140}
141
142template<typename TargetValueType, typename ExactValueType, typename ImpreciseValueType, bool TrivialRowGrouping>
143template<storm::OptimizationDirection Dir>
145 std::vector<TargetValueType>& operand, std::vector<TargetValueType> const& offsets, uint64_t& numIterations, TargetValueType const& precision,
146 std::function<SolverStatus(SolverStatus const&)> const& iterationCallback) const {
147 if constexpr (std::is_same_v<TargetValueType, ExactValueType>) {
148 // We need an exact solution
149 // We first try to solve the problem using imprecise values and fall back to exact values if needed.
150 auto& impreciseOperand = impreciseOperator->allocateAuxiliaryVector(operand.size());
151 storm::utility::vector::convertNumericVector(operand, impreciseOperand);
152 auto impreciseOffsets = storm::utility::vector::convertNumericVector<ImpreciseValueType>(offsets);
153 auto [result, status] = RS<ImpreciseValueType, Dir>(impreciseOperand, impreciseOffsets, numIterations, precision, offsets, operand, iterationCallback);
154 if (result != RSResult::PrecisionExceeded) {
155 return status;
156 }
157 STORM_LOG_WARN("Precision of value type was exceeded, trying to recover by switching to rational arithmetic.");
158 storm::utility::vector::convertNumericVector(impreciseOperand, operand);
159 return RS<TargetValueType, Dir>(operand, offsets, numIterations, precision, offsets, operand, iterationCallback).second;
160 } else {
161 // We only try with the inexact type
162 auto exactOffsets = storm::utility::vector::convertNumericVector<ExactValueType>(offsets);
163 return RS<TargetValueType, Dir>(operand, offsets, numIterations, storm::utility::convertNumber<ExactValueType>(precision), exactOffsets, operand,
164 iterationCallback)
165 .second;
166 }
167}
168
169template<typename TargetValueType, typename ExactValueType, typename ImpreciseValueType, bool TrivialRowGrouping>
171 std::vector<TargetValueType>& operand, std::vector<TargetValueType> const& offsets, uint64_t& numIterations, TargetValueType const& precision,
172 std::optional<storm::OptimizationDirection> const& dir, std::function<SolverStatus(SolverStatus const&)> const& iterationCallback) const {
173 STORM_LOG_ASSERT(TrivialRowGrouping || dir.has_value(), "no optimization direction given!");
174 if (!dir.has_value() || maximize(*dir)) {
175 return RS<storm::OptimizationDirection::Maximize>(operand, offsets, numIterations, precision, iterationCallback);
176 } else {
177 return RS<storm::OptimizationDirection::Minimize>(operand, offsets, numIterations, precision, iterationCallback);
178 }
179}
180
181template<typename TargetValueType, typename ExactValueType, typename ImpreciseValueType, bool TrivialRowGrouping>
183 std::vector<TargetValueType>& operand, std::vector<TargetValueType> const& offsets, TargetValueType const& precision,
184 std::optional<storm::OptimizationDirection> const& dir, std::function<SolverStatus(SolverStatus const&)> const& iterationCallback) const {
185 uint64_t numIterations = 0;
186 return RS(operand, offsets, numIterations, precision, dir, iterationCallback);
187}
188
193
194} // namespace storm::solver::helper
void firstRow(ExactValueType &&value, uint64_t rowGroup, uint64_t row)
void nextRow(ExactValueType &&value, uint64_t rowGroup, uint64_t row)
void applyUpdate(ExactValueType &currValue, uint64_t rowGroup)
SolverStatus RS(std::vector< TargetValueType > &operand, std::vector< TargetValueType > const &offsets, uint64_t &numIterations, TargetValueType const &precision, std::function< SolverStatus(SolverStatus const &)> const &iterationCallback={}) const
RationalSearchHelper(std::shared_ptr< ValueIterationOperator< ExactValueType, TrivialRowGrouping > > exactViOperator, std::shared_ptr< ValueIterationOperator< ImpreciseValueType, TrivialRowGrouping > > impreciseViOperator)
This class represents the Value Iteration Operator (also known as Bellman operator).
Stores and manages an extremal (maximal or minimal) value.
Definition Extremum.h:15
#define STORM_LOG_WARN(message)
Definition logging.h:25
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
bool constexpr maximize(OptimizationDirection d)
RationalType sharpen(uint64_t precision, ImpreciseType const &value)
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...
Definition vector.h:966
ValueType ceil(ValueType const &number)