45 template<
bool Backward = true>
93 template<
typename OperandType,
typename OffsetType,
typename BackendType>
94 bool apply(OperandType
const& operandIn, OperandType& operandOut, OffsetType
const& offsets, BackendType& backend)
const {
96 return applyRobust<OptimizationDirection::Maximize>(operandIn, operandOut, offsets, backend);
99 template<OptimizationDirection RobustDir,
typename OperandType,
typename OffsetType,
typename BackendType>
100 bool applyRobust(OperandType
const& operandIn, OperandType& operandOut, OffsetType
const& offsets, BackendType& backend)
const {
101 if (hasSkippedRows) {
103 return apply<OperandType, OffsetType, BackendType, true, true, RobustDir>(operandOut, operandIn, offsets, backend);
105 return apply<OperandType, OffsetType, BackendType, false, true, RobustDir>(operandOut, operandIn, offsets, backend);
109 return apply<OperandType, OffsetType, BackendType, true, false, RobustDir>(operandOut, operandIn, offsets, backend);
111 return apply<OperandType, OffsetType, BackendType, false, false, RobustDir>(operandOut, operandIn, offsets, backend);
119 template<
typename OperandType,
typename OffsetType,
typename BackendType>
120 bool applyInPlace(OperandType& operand, OffsetType
const& offsets, BackendType& backend)
const {
121 return apply(operand, operand, offsets, backend);
124 template<OptimizationDirection RobustDir,
typename OperandType,
typename OffsetType,
typename BackendType>
125 bool applyInPlaceRobust(OperandType& operand, OffsetType
const& offsets, BackendType& backend)
const {
126 return applyRobust<RobustDir>(operand, operand, offsets, backend);
154 std::vector<SolutionType>&
allocateAuxiliaryVector(uint64_t size, std::optional<SolutionType>
const& initialValue = {});
166 template<
typename OperandType,
typename OffsetType,
typename BackendType,
bool Backward,
bool SkipIgnoredRows, OptimizationDirection RobustDirection>
167 bool apply(OperandType& operandOut, OperandType
const& operandIn, OffsetType
const& offsets, BackendType& backend)
const {
168 auto const outSize = TrivialRowGrouping ? getSize(operandOut) : rowGroupIndices->size() - 1;
169 STORM_LOG_ASSERT(TrivialRowGrouping || getSize(operandOut) >= outSize,
"Dimension mismatch");
170 backend.startNewIteration();
171 auto matrixValueIt = matrixValues.cbegin();
172 auto matrixColumnIt = matrixColumns.cbegin();
173 for (
auto groupIndex : indexRange<Backward>(0, outSize)) {
174 STORM_LOG_ASSERT(matrixColumnIt != matrixColumns.end(),
"VI Operator in invalid state.");
175 STORM_LOG_ASSERT(*matrixColumnIt >= StartOfRowIndicator,
"VI Operator in invalid state.");
177 if constexpr (TrivialRowGrouping) {
178 backend.firstRow(applyRow<RobustDirection>(matrixColumnIt, matrixValueIt, operandIn, offsets, groupIndex), groupIndex, groupIndex);
180 IndexType rowIndex = (*rowGroupIndices)[groupIndex];
181 if constexpr (SkipIgnoredRows) {
182 rowIndex += skipMultipleIgnoredRows(matrixColumnIt, matrixValueIt);
184 backend.firstRow(applyRow<RobustDirection>(matrixColumnIt, matrixValueIt, operandIn, offsets, rowIndex), groupIndex, rowIndex);
185 while (*matrixColumnIt < StartOfRowGroupIndicator) {
187 if (!SkipIgnoredRows || !skipIgnoredRow(matrixColumnIt, matrixValueIt)) {
188 backend.nextRow(applyRow<RobustDirection>(matrixColumnIt, matrixValueIt, operandIn, offsets, rowIndex), groupIndex, rowIndex);
192 if constexpr (isPair<OperandType>::value) {
193 backend.applyUpdate(operandOut.first[groupIndex], operandOut.second[groupIndex], groupIndex);
195 backend.applyUpdate(operandOut[groupIndex], groupIndex);
197 if (backend.abort()) {
198 return backend.converged();
201 STORM_LOG_ASSERT(matrixColumnIt + 1 == matrixColumns.cend(),
"Unexpected position of matrix column iterator.");
202 STORM_LOG_ASSERT(matrixValueIt == matrixValues.cend(),
"Unexpected position of matrix column iterator.");
203 backend.endOfIteration();
204 return backend.converged();
209 template<
typename OpT>
210 OpT initializeRowRes(std::vector<OpT>
const&, OpT
const& offsets, uint64_t offsetIndex)
const {
214 template<
typename OpT,
typename OffT>
215 OpT initializeRowRes(std::vector<OpT>
const&, std::vector<OffT>
const& offsets, uint64_t offsetIndex)
const {
216 return offsets[offsetIndex];
219 template<
typename OpT1,
typename OpT2,
typename OffT>
220 std::pair<OpT1, OpT2> initializeRowRes(std::pair<std::vector<OpT1>, std::vector<OpT2>>
const&, std::vector<OffT>
const& offsets,
221 uint64_t offsetIndex)
const {
222 return {offsets[offsetIndex], offsets[offsetIndex]};
225 template<
typename OpT1,
typename OpT2,
typename OffT1,
typename OffT2>
226 std::pair<OpT1, OpT2> initializeRowRes(std::pair<std::vector<OpT1>, std::vector<OpT2>>
const&, std::pair<std::vector<OffT1>
const*, OffT2>
const& offsets,
227 uint64_t offsetIndex)
const {
228 return {(*offsets.first)[offsetIndex], offsets.second};
231 template<OptimizationDirection RobustDirection,
typename OpT,
typename OffT>
232 OpT robustInitializeRowRes(std::vector<OpT>
const&, std::vector<OffT>
const& offsets, uint64_t offsetIndex)
const {
233 return offsets[offsetIndex].upper();
236 template<OptimizationDirection RobustDirection,
typename OpT1,
typename OpT2,
typename OffT>
237 std::pair<OpT1, OpT2> robustInitializeRowRes(std::pair<std::vector<OpT1>, std::vector<OpT2>>
const&, std::vector<OffT>
const& offsets,
238 uint64_t offsetIndex)
const {
239 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Value Iteration is not implemented with pairs and interval-models.");
241 return {offsets[offsetIndex].upper(), offsets[offsetIndex].upper()};
244 template<OptimizationDirection RobustDirection,
typename OpT1,
typename OpT2,
typename OffT1,
typename OffT2>
245 std::pair<OpT1, OpT2> robustInitializeRowRes(std::pair<std::vector<OpT1>, std::vector<OpT2>>
const&,
246 std::pair<std::vector<OffT1>
const*, OffT2>
const& offsets, uint64_t offsetIndex)
const {
247 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Value Iteration is not implemented with pairs and interval-models.");
249 return {(*offsets.first)[offsetIndex], offsets.second};
255 template<OptimizationDirection RobustDirection,
typename OperandType,
typename OffsetType>
256 auto applyRow(std::vector<IndexType>::const_iterator& matrixColumnIt,
typename std::vector<ValueType>::const_iterator& matrixValueIt,
257 OperandType
const& operand, OffsetType
const& offsets, uint64_t offsetIndex)
const {
258 if constexpr (std::is_same_v<ValueType, storm::Interval>) {
259 return applyRowRobust<RobustDirection>(matrixColumnIt, matrixValueIt, operand, offsets, offsetIndex);
261 return applyRowStandard(matrixColumnIt, matrixValueIt, operand, offsets, offsetIndex);
265 template<
typename OperandType,
typename OffsetType>
266 auto applyRowStandard(std::vector<IndexType>::const_iterator& matrixColumnIt,
typename std::vector<ValueType>::const_iterator& matrixValueIt,
267 OperandType
const& operand, OffsetType
const& offsets, uint64_t offsetIndex)
const {
268 STORM_LOG_ASSERT(*matrixColumnIt >= StartOfRowIndicator,
"VI Operator in invalid state.");
269 auto result{initializeRowRes(operand, offsets, offsetIndex)};
270 for (++matrixColumnIt; *matrixColumnIt < StartOfRowIndicator; ++matrixColumnIt, ++matrixValueIt) {
271 if constexpr (isPair<OperandType>::value) {
272 result.first += operand.first[*matrixColumnIt] * (*matrixValueIt);
273 result.second += operand.second[*matrixColumnIt] * (*matrixValueIt);
275 result += operand[*matrixColumnIt] * (*matrixValueIt);
282 template<OptimizationDirection RobustDirection>
284 bool operator()(
const std::pair<SolutionType, SolutionType>& a,
const std::pair<SolutionType, SolutionType>& b)
const {
285 if constexpr (RobustDirection == OptimizationDirection::Maximize) {
286 return a.first > b.first;
288 return a.first < b.first;
293 template<OptimizationDirection RobustDirection,
typename OperandType,
typename OffsetType>
294 auto applyRowRobust(std::vector<IndexType>::const_iterator& matrixColumnIt,
typename std::vector<ValueType>::const_iterator& matrixValueIt,
295 OperandType
const& operand, OffsetType
const& offsets, uint64_t offsetIndex)
const {
296 STORM_LOG_ASSERT(*matrixColumnIt >= StartOfRowIndicator,
"VI Operator in invalid state.");
297 auto result{robustInitializeRowRes<RobustDirection>(operand, offsets, offsetIndex)};
298 AuxCompare<RobustDirection> compare;
299 applyCache.robustOrder.clear();
301 SolutionType remainingValue{storm::utility::one<SolutionType>()};
302 for (++matrixColumnIt; *matrixColumnIt < StartOfRowIndicator; ++matrixColumnIt, ++matrixValueIt) {
303 auto const lower = matrixValueIt->lower();
304 if constexpr (isPair<OperandType>::value) {
305 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Value Iteration is not implemented with pairs and interval-models.");
308 result += operand[*matrixColumnIt] * lower;
310 remainingValue -= lower;
311 auto const diameter = matrixValueIt->upper() - lower;
313 applyCache.robustOrder.emplace_back(operand[*matrixColumnIt], diameter);
320 std::sort(applyCache.robustOrder.begin(), applyCache.robustOrder.end(), compare);
322 for (
auto const& pair : applyCache.robustOrder) {
323 auto availableMass = std::min(pair.second, remainingValue);
324 result += availableMass * pair.first;
325 remainingValue -= availableMass;
335 template<
bool Backward>
337 if constexpr (Backward) {
338 return boost::adaptors::reverse(boost::irange(start, end));
340 return boost::irange(start, end);
345 uint64_t getSize(std::vector<T>
const& vec)
const {
349 template<
typename T1,
typename T2>
350 uint64_t getSize(std::pair<T1, T2>
const& pairOfVec)
const {
351 return pairOfVec.first.size();
355 struct isPair : std::false_type {};
357 template<
typename T1,
typename T2>
358 struct isPair<
std::pair<T1, T2>> : std::true_type {};
363 template<
bool Backward = true>
369 void moveToEndOfRow(std::vector<IndexType>::iterator& matrixColumnIt)
const;
374 bool skipIgnoredRow(std::vector<IndexType>::const_iterator& matrixColumnIt,
typename std::vector<ValueType>::const_iterator& matrixValueIt)
const;
379 uint64_t skipMultipleIgnoredRows(std::vector<IndexType>::const_iterator& matrixColumnIt,
380 typename std::vector<ValueType>::const_iterator& matrixValueIt)
const;
385 std::vector<ValueType> matrixValues;
391 std::vector<IndexType> matrixColumns;
396 std::vector<IndexType>
const* rowGroupIndices;
401 bool backwards{
true};
406 bool hasSkippedRows{
false};
411 std::vector<SolutionType> auxiliaryVector;
416 bool auxiliaryVectorUsedExternally{
false};
420 template<
typename ApplyValueType,
typename Dummy>
421 struct ApplyCache {};
423 template<
typename Dummy>
425 mutable std::vector<std::pair<SolutionType, SolutionType>> robustOrder;
431 ApplyCache<ValueType, int> applyCache;
436 static constexpr IndexType StartOfRowIndicator = 1ull << 63;
441 static constexpr IndexType StartOfRowGroupIndicator = StartOfRowIndicator + (1ull << 62);
446 static constexpr IndexType SkipNumEntriesMask = ~StartOfRowGroupIndicator;