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