51 template<
bool Backward = true>
99 template<
typename OperandType,
typename OffsetType,
typename BackendType>
100 bool apply(OperandType
const& operandIn, OperandType& operandOut, OffsetType
const& offsets, BackendType& backend)
const {
102 return applyRobust<OptimizationDirection::Maximize>(operandIn, operandOut, offsets, backend);
105 template<OptimizationDirection RobustDir,
typename OperandType,
typename OffsetType,
typename BackendType>
106 bool applyRobust(OperandType
const& operandIn, OperandType& operandOut, OffsetType
const& offsets, BackendType& backend)
const {
107 if (hasSkippedRows) {
109 return apply<OperandType, OffsetType, BackendType, true, true, RobustDir>(operandOut, operandIn, offsets, backend);
111 return apply<OperandType, OffsetType, BackendType, false, true, RobustDir>(operandOut, operandIn, offsets, backend);
115 return apply<OperandType, OffsetType, BackendType, true, false, RobustDir>(operandOut, operandIn, offsets, backend);
117 return apply<OperandType, OffsetType, BackendType, false, false, RobustDir>(operandOut, operandIn, offsets, backend);
125 template<
typename OperandType,
typename OffsetType,
typename BackendType>
126 bool applyInPlace(OperandType& operand, OffsetType
const& offsets, BackendType& backend)
const {
127 return apply(operand, operand, offsets, backend);
130 template<OptimizationDirection RobustDir,
typename OperandType,
typename OffsetType,
typename BackendType>
131 bool applyInPlaceRobust(OperandType& operand, OffsetType
const& offsets, BackendType& backend)
const {
132 return applyRobust<RobustDir>(operand, operand, offsets, backend);
160 std::vector<SolutionType>&
allocateAuxiliaryVector(uint64_t size, std::optional<SolutionType>
const& initialValue = {});
172 template<
typename OperandType,
typename OffsetType,
typename BackendType,
bool Backward,
bool SkipIgnoredRows, OptimizationDirection RobustDirection>
173 bool apply(OperandType& operandOut, OperandType
const& operandIn, OffsetType
const& offsets, BackendType& backend)
const {
174 auto const outSize = TrivialRowGrouping ? getSize(operandOut) : rowGroupIndices->size() - 1;
175 STORM_LOG_ASSERT(TrivialRowGrouping || getSize(operandOut) >= outSize,
"Dimension mismatch");
176 backend.startNewIteration();
177 auto matrixValueIt = matrixValues.cbegin();
178 auto matrixColumnIt = matrixColumns.cbegin();
179 for (
auto groupIndex : indexRange<Backward>(0, outSize)) {
180 STORM_LOG_ASSERT(matrixColumnIt != matrixColumns.end(),
"VI Operator in invalid state.");
181 STORM_LOG_ASSERT(*matrixColumnIt >= StartOfRowIndicator,
"VI Operator in invalid state.");
182 if constexpr (TrivialRowGrouping) {
184 if constexpr (std::is_same<BackendType, RobustSchedulerTrackingBackend<double, RobustDirection, TrivialRowGrouping>>::value) {
186 backend.processRobustRow(applyRow<RobustDirection>(matrixColumnIt, matrixValueIt, operandIn, offsets, groupIndex), groupIndex,
187 applyCache.robustOrder);
190 backend.firstRow(applyRow<RobustDirection>(matrixColumnIt, matrixValueIt, operandIn, offsets, groupIndex), groupIndex, groupIndex);
193 IndexType rowIndex = (*rowGroupIndices)[groupIndex];
194 if constexpr (SkipIgnoredRows) {
195 rowIndex += skipMultipleIgnoredRows(matrixColumnIt, matrixValueIt);
197 backend.firstRow(applyRow<RobustDirection>(matrixColumnIt, matrixValueIt, operandIn, offsets, rowIndex), groupIndex, rowIndex);
198 while (*matrixColumnIt < StartOfRowGroupIndicator) {
200 if (!SkipIgnoredRows || !skipIgnoredRow(matrixColumnIt, matrixValueIt)) {
201 backend.nextRow(applyRow<RobustDirection>(matrixColumnIt, matrixValueIt, operandIn, offsets, rowIndex), groupIndex, rowIndex);
205 if constexpr (isPair<OperandType>::value) {
206 backend.applyUpdate(operandOut.first[groupIndex], operandOut.second[groupIndex], groupIndex);
208 backend.applyUpdate(operandOut[groupIndex], groupIndex);
210 if (backend.abort()) {
211 return backend.converged();
214 STORM_LOG_ASSERT(matrixColumnIt + 1 == matrixColumns.cend(),
"Unexpected position of matrix column iterator.");
215 STORM_LOG_ASSERT(matrixValueIt == matrixValues.cend(),
"Unexpected position of matrix column iterator.");
216 backend.endOfIteration();
217 return backend.converged();
222 template<
typename OpT>
223 OpT initializeRowRes(std::vector<OpT>
const&, OpT
const& offsets, uint64_t offsetIndex)
const {
227 template<
typename OpT,
typename OffT>
228 OpT initializeRowRes(std::vector<OpT>
const&, std::vector<OffT>
const& offsets, uint64_t offsetIndex)
const {
229 return offsets[offsetIndex];
232 template<
typename OpT1,
typename OpT2,
typename OffT>
233 std::pair<OpT1, OpT2> initializeRowRes(std::pair<std::vector<OpT1>, std::vector<OpT2>>
const&, std::vector<OffT>
const& offsets,
234 uint64_t offsetIndex)
const {
235 return {offsets[offsetIndex], offsets[offsetIndex]};
238 template<
typename OpT1,
typename OpT2,
typename OffT1,
typename OffT2>
239 std::pair<OpT1, OpT2> initializeRowRes(std::pair<std::vector<OpT1>, std::vector<OpT2>>
const&, std::pair<std::vector<OffT1>
const*, OffT2>
const& offsets,
240 uint64_t offsetIndex)
const {
241 return {(*offsets.first)[offsetIndex], offsets.second};
244 template<OptimizationDirection RobustDirection,
typename OpT,
typename OffT>
245 OpT robustInitializeRowRes(std::vector<OpT>
const&, std::vector<OffT>
const& offsets, uint64_t offsetIndex)
const {
246 if constexpr (RobustDirection == OptimizationDirection::Maximize) {
247 return offsets[offsetIndex].upper();
249 return offsets[offsetIndex].lower();
253 template<OptimizationDirection RobustDirection,
typename OpT1,
typename OpT2,
typename OffT>
254 std::pair<OpT1, OpT2> robustInitializeRowRes(std::pair<std::vector<OpT1>, std::vector<OpT2>>
const&, std::vector<OffT>
const& offsets,
255 uint64_t offsetIndex)
const {
256 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Value Iteration is not implemented with pairs and interval-models.");
258 return {offsets[offsetIndex].upper(), offsets[offsetIndex].upper()};
261 template<OptimizationDirection RobustDirection,
typename OpT1,
typename OpT2,
typename OffT1,
typename OffT2>
262 std::pair<OpT1, OpT2> robustInitializeRowRes(std::pair<std::vector<OpT1>, std::vector<OpT2>>
const&,
263 std::pair<std::vector<OffT1>
const*, OffT2>
const& offsets, uint64_t offsetIndex)
const {
264 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Value Iteration is not implemented with pairs and interval-models.");
266 return {(*offsets.first)[offsetIndex], offsets.second};
272 template<OptimizationDirection RobustDirection,
typename OperandType,
typename OffsetType>
273 auto applyRow(std::vector<IndexType>::const_iterator& matrixColumnIt,
typename std::vector<ValueType>::const_iterator& matrixValueIt,
274 OperandType
const& operand, OffsetType
const& offsets, uint64_t offsetIndex)
const {
275 if constexpr (std::is_same_v<ValueType, storm::Interval>) {
276 return applyRowRobust<RobustDirection>(matrixColumnIt, matrixValueIt, operand, offsets, offsetIndex);
278 return applyRowStandard(matrixColumnIt, matrixValueIt, operand, offsets, offsetIndex);
282 template<
typename OperandType,
typename OffsetType>
283 auto applyRowStandard(std::vector<IndexType>::const_iterator& matrixColumnIt,
typename std::vector<ValueType>::const_iterator& matrixValueIt,
284 OperandType
const& operand, OffsetType
const& offsets, uint64_t offsetIndex)
const {
285 STORM_LOG_ASSERT(*matrixColumnIt >= StartOfRowIndicator,
"VI Operator in invalid state.");
286 auto result{initializeRowRes(operand, offsets, offsetIndex)};
287 for (++matrixColumnIt; *matrixColumnIt < StartOfRowIndicator; ++matrixColumnIt, ++matrixValueIt) {
288 if constexpr (isPair<OperandType>::value) {
289 result.first += operand.first[*matrixColumnIt] * (*matrixValueIt);
290 result.second += operand.second[*matrixColumnIt] * (*matrixValueIt);
292 result += operand[*matrixColumnIt] * (*matrixValueIt);
299 template<OptimizationDirection RobustDirection>
301 bool operator()(
const std::pair<SolutionType, std::pair<SolutionType, uint64_t>>& a,
302 const std::pair<SolutionType, std::pair<SolutionType, uint64_t>>& b)
const {
303 if constexpr (RobustDirection == OptimizationDirection::Maximize) {
304 return a.first > b.first;
306 return a.first < b.first;
311 template<OptimizationDirection RobustDirection,
typename OperandType,
typename OffsetType>
312 auto applyRowRobust(std::vector<IndexType>::const_iterator& matrixColumnIt,
typename std::vector<ValueType>::const_iterator& matrixValueIt,
313 OperandType
const& operand, OffsetType
const& offsets, uint64_t offsetIndex)
const {
314 STORM_LOG_ASSERT(*matrixColumnIt >= StartOfRowIndicator,
"VI Operator in invalid state.");
315 auto result{robustInitializeRowRes<RobustDirection>(operand, offsets, offsetIndex)};
317 applyCache.robustOrder.clear();
319 if (applyCache.hasOnlyConstants.size() > 0 && applyCache.hasOnlyConstants.get(offsetIndex)) {
320 for (++matrixColumnIt; *matrixColumnIt < StartOfRowIndicator; ++matrixColumnIt, ++matrixValueIt) {
321 auto const lower = matrixValueIt->lower();
322 if constexpr (isPair<OperandType>::value) {
323 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Value Iteration is not implemented with pairs and interval-models.");
326 result += operand[*matrixColumnIt] * lower;
332 SolutionType remainingValue{storm::utility::one<SolutionType>()};
333 uint64_t orderCounter = 0;
334 for (++matrixColumnIt; *matrixColumnIt < StartOfRowIndicator; ++matrixColumnIt, ++matrixValueIt, ++orderCounter) {
335 auto const lower = matrixValueIt->lower();
336 if constexpr (isPair<OperandType>::value) {
337 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Value Iteration is not implemented with pairs and interval-models.");
340 result += operand[*matrixColumnIt] * lower;
342 remainingValue -= lower;
343 auto const diameter = matrixValueIt->upper() - lower;
345 applyCache.robustOrder.emplace_back(operand[*matrixColumnIt], std::make_pair(diameter, orderCounter));
352 static AuxCompare<RobustDirection> cmp;
353 std::sort(applyCache.robustOrder.begin(), applyCache.robustOrder.end(), cmp);
355 for (
auto const& pair : applyCache.robustOrder) {
356 auto availableMass = std::min(pair.second.first, remainingValue);
357 result += availableMass * pair.first;
358 remainingValue -= availableMass;
366 "Remaining value should be zero (all prob mass taken) or it should be a sad state, but is " << remainingValue);
371 template<
bool Backward>
373 if constexpr (Backward) {
374 return boost::adaptors::reverse(boost::irange(start, end));
376 return boost::irange(start, end);
381 uint64_t getSize(std::vector<T>
const& vec)
const {
385 template<
typename T1,
typename T2>
386 uint64_t getSize(std::pair<T1, T2>
const& pairOfVec)
const {
387 return pairOfVec.first.size();
391 struct isPair : std::false_type {};
393 template<
typename T1,
typename T2>
394 struct isPair<
std::pair<T1, T2>> : std::true_type {};
399 template<
bool Backward = true>
405 void moveToEndOfRow(std::vector<IndexType>::iterator& matrixColumnIt)
const;
410 bool skipIgnoredRow(std::vector<IndexType>::const_iterator& matrixColumnIt,
typename std::vector<ValueType>::const_iterator& matrixValueIt)
const;
415 uint64_t skipMultipleIgnoredRows(std::vector<IndexType>::const_iterator& matrixColumnIt,
416 typename std::vector<ValueType>::const_iterator& matrixValueIt)
const;
421 std::vector<ValueType> matrixValues;
427 std::vector<IndexType> matrixColumns;
432 std::vector<IndexType>
const* rowGroupIndices;
437 bool backwards{
true};
442 bool hasSkippedRows{
false};
447 std::vector<SolutionType> auxiliaryVector;
452 bool auxiliaryVectorUsedExternally{
false};
456 template<
typename ApplyValueType,
typename Dummy>
457 struct ApplyCache {};
459 template<
typename Dummy>
461 mutable std::vector<std::pair<SolutionType, std::pair<SolutionType, uint64_t>>> robustOrder;
462 storage::BitVector hasOnlyConstants;
468 ApplyCache<ValueType, int> applyCache;
473 static constexpr IndexType StartOfRowIndicator = 1ull << 63;
478 static constexpr IndexType StartOfRowGroupIndicator = StartOfRowIndicator + (1ull << 62);
483 static constexpr IndexType SkipNumEntriesMask = ~StartOfRowGroupIndicator;