|
|
@ -582,7 +582,8 @@ namespace storm { |
|
|
|
} |
|
|
|
|
|
|
|
reportStatus(status, iterations); |
|
|
|
|
|
|
|
this->overallPerformedIterations += iterations; |
|
|
|
|
|
|
|
// We take the means of the lower and upper bound so we guarantee the desired precision.
|
|
|
|
ValueType two = storm::utility::convertNumber<ValueType>(2.0); |
|
|
|
storm::utility::vector::applyPointwise<ValueType, ValueType, ValueType>(*lowerX, *upperX, *lowerX, [&two] (ValueType const& a, ValueType const& b) -> ValueType { return (a + b) / two; }); |
|
|
@ -718,90 +719,6 @@ namespace storm { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void performIterationStepMax(storm::storage::SparseMatrix<ValueType> const& A, std::vector<ValueType> const& b) { |
|
|
|
if (!decisionValueBlocks) { |
|
|
|
performIterationStepUpdateDecisionValueMax(A, b); |
|
|
|
} else { |
|
|
|
assert(decisionValue == upperBound); |
|
|
|
auto xIt = x.rbegin(); |
|
|
|
auto yIt = y.rbegin(); |
|
|
|
auto groupStartIt = A.getRowGroupIndices().rbegin(); |
|
|
|
uint64_t groupEnd = *groupStartIt; |
|
|
|
++groupStartIt; |
|
|
|
for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { |
|
|
|
// Perform the iteration for the first row in the group
|
|
|
|
uint64_t row = *groupStartIt; |
|
|
|
ValueType xBest, yBest; |
|
|
|
multiplyRow(row, A, b[row], xBest, yBest); |
|
|
|
++row; |
|
|
|
// Only do more work if there are still rows in this row group
|
|
|
|
if (row != groupEnd) { |
|
|
|
ValueType xi, yi; |
|
|
|
ValueType bestValue = xBest + yBest * upperBound; |
|
|
|
for (;row < groupEnd; ++row) { |
|
|
|
// Get the multiplication results
|
|
|
|
multiplyRow(row, A, b[row], xi, yi); |
|
|
|
ValueType currentValue = xi + yi * upperBound; |
|
|
|
// Check if the current row is better then the previously found one
|
|
|
|
if (currentValue > bestValue) { |
|
|
|
xBest = std::move(xi); |
|
|
|
yBest = std::move(yi); |
|
|
|
bestValue = std::move(currentValue); |
|
|
|
} else if (currentValue == bestValue && yBest > yi) { |
|
|
|
// If the value for this row is not strictly better, it might still be equal and have a better y value
|
|
|
|
xBest = std::move(xi); |
|
|
|
yBest = std::move(yi); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
*xIt = std::move(xBest); |
|
|
|
*yIt = std::move(yBest); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void performIterationStepMin(storm::storage::SparseMatrix<ValueType> const& A, std::vector<ValueType> const& b) { |
|
|
|
if (!decisionValueBlocks) { |
|
|
|
performIterationStepUpdateDecisionValueMin(A, b); |
|
|
|
} else { |
|
|
|
assert(decisionValue == lowerBound); |
|
|
|
auto xIt = x.rbegin(); |
|
|
|
auto yIt = y.rbegin(); |
|
|
|
auto groupStartIt = A.getRowGroupIndices().rbegin(); |
|
|
|
uint64_t groupEnd = *groupStartIt; |
|
|
|
++groupStartIt; |
|
|
|
for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { |
|
|
|
// Perform the iteration for the first row in the group
|
|
|
|
uint64_t row = *groupStartIt; |
|
|
|
ValueType xBest, yBest; |
|
|
|
multiplyRow(row, A, b[row], xBest, yBest); |
|
|
|
++row; |
|
|
|
// Only do more work if there are still rows in this row group
|
|
|
|
if (row != groupEnd) { |
|
|
|
ValueType xi, yi; |
|
|
|
ValueType bestValue = xBest + yBest * lowerBound; |
|
|
|
for (;row < groupEnd; ++row) { |
|
|
|
// Get the multiplication results
|
|
|
|
multiplyRow(row, A, b[row], xi, yi); |
|
|
|
ValueType currentValue = xi + yi * lowerBound; |
|
|
|
// Check if the current row is better then the previously found one
|
|
|
|
if (currentValue < bestValue) { |
|
|
|
xBest = std::move(xi); |
|
|
|
yBest = std::move(yi); |
|
|
|
bestValue = std::move(currentValue); |
|
|
|
} else if (currentValue == bestValue && yBest > yi) { |
|
|
|
// If the value for this row is not strictly better, it might still be equal and have a better y value
|
|
|
|
xBest = std::move(xi); |
|
|
|
yBest = std::move(yi); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
*xIt = std::move(xBest); |
|
|
|
*yIt = std::move(yBest); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template<OptimizationDirection dir> |
|
|
|
void performIterationStepUpdateDecisionValue(storm::storage::SparseMatrix<ValueType> const& A, std::vector<ValueType> const& b) { |
|
|
|
auto xIt = x.rbegin(); |
|
|
@ -883,166 +800,6 @@ namespace storm { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void performIterationStepUpdateDecisionValueMax(storm::storage::SparseMatrix<ValueType> const& A, std::vector<ValueType> const& b) { |
|
|
|
auto xIt = x.rbegin(); |
|
|
|
auto yIt = y.rbegin(); |
|
|
|
auto groupStartIt = A.getRowGroupIndices().rbegin(); |
|
|
|
uint64_t groupEnd = *groupStartIt; |
|
|
|
++groupStartIt; |
|
|
|
for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { |
|
|
|
// Perform the iteration for the first row in the group
|
|
|
|
uint64_t row = *groupStartIt; |
|
|
|
ValueType xBest, yBest; |
|
|
|
multiplyRow(row, A, b[row], xBest, yBest); |
|
|
|
++row; |
|
|
|
// Only do more work if there are still rows in this row group
|
|
|
|
if (row != groupEnd) { |
|
|
|
ValueType xi, yi; |
|
|
|
uint64_t xyTmpIndex = 0; |
|
|
|
if (hasUpperBound) { |
|
|
|
ValueType bestValue = xBest + yBest * upperBound; |
|
|
|
for (;row < groupEnd; ++row) { |
|
|
|
// Get the multiplication results
|
|
|
|
multiplyRow(row, A, b[row], xi, yi); |
|
|
|
ValueType currentValue = xi + yi * upperBound; |
|
|
|
// Check if the current row is better then the previously found one
|
|
|
|
if (currentValue > bestValue) { |
|
|
|
if (yBest < yi) { |
|
|
|
// We need to store the 'old' best value as it might be relevant for the decision value
|
|
|
|
xTmp[xyTmpIndex] = std::move(xBest); |
|
|
|
yTmp[xyTmpIndex] = std::move(yBest); |
|
|
|
++xyTmpIndex; |
|
|
|
} |
|
|
|
xBest = std::move(xi); |
|
|
|
yBest = std::move(yi); |
|
|
|
bestValue = std::move(currentValue); |
|
|
|
} else if (yBest > yi) { |
|
|
|
// If the value for this row is not strictly better, it might still be equal and have a better y value
|
|
|
|
if (currentValue == bestValue) { |
|
|
|
xBest = std::move(xi); |
|
|
|
yBest = std::move(yi); |
|
|
|
} else { |
|
|
|
xTmp[xyTmpIndex] = std::move(xi); |
|
|
|
yTmp[xyTmpIndex] = std::move(yi); |
|
|
|
++xyTmpIndex; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
for (;row < groupEnd; ++row) { |
|
|
|
multiplyRow(row, A, b[row], xi, yi); |
|
|
|
// Update the best choice
|
|
|
|
if (yi > yBest || (yi == yBest && xi > xBest)) { |
|
|
|
xTmp[xyTmpIndex] = std::move(xBest); |
|
|
|
yTmp[xyTmpIndex] = std::move(yBest); |
|
|
|
++xyTmpIndex; |
|
|
|
xBest = std::move(xi); |
|
|
|
yBest = std::move(yi); |
|
|
|
} else { |
|
|
|
xTmp[xyTmpIndex] = std::move(xi); |
|
|
|
yTmp[xyTmpIndex] = std::move(yi); |
|
|
|
++xyTmpIndex; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Update the decision value
|
|
|
|
for (uint64_t i = 0; i < xyTmpIndex; ++i) { |
|
|
|
ValueType deltaY = yBest - yTmp[i]; |
|
|
|
if (deltaY > storm::utility::zero<ValueType>()) { |
|
|
|
ValueType newDecisionValue = (xTmp[i] - xBest) / deltaY; |
|
|
|
if (!hasDecisionValue || newDecisionValue > decisionValue) { |
|
|
|
decisionValue = std::move(newDecisionValue); |
|
|
|
hasDecisionValue = true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
*xIt = std::move(xBest); |
|
|
|
*yIt = std::move(yBest); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void performIterationStepUpdateDecisionValueMin(storm::storage::SparseMatrix<ValueType> const& A, std::vector<ValueType> const& b) { |
|
|
|
auto xIt = x.rbegin(); |
|
|
|
auto yIt = y.rbegin(); |
|
|
|
auto groupStartIt = A.getRowGroupIndices().rbegin(); |
|
|
|
uint64_t groupEnd = *groupStartIt; |
|
|
|
++groupStartIt; |
|
|
|
for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { |
|
|
|
// Perform the iteration for the first row in the group
|
|
|
|
uint64_t row = *groupStartIt; |
|
|
|
ValueType xBest, yBest; |
|
|
|
multiplyRow(row, A, b[row], xBest, yBest); |
|
|
|
++row; |
|
|
|
// Only do more work if there are still rows in this row group
|
|
|
|
if (row != groupEnd) { |
|
|
|
ValueType xi, yi; |
|
|
|
uint64_t xyTmpIndex = 0; |
|
|
|
if (hasLowerBound) { |
|
|
|
ValueType bestValue = xBest + yBest * lowerBound; |
|
|
|
for (;row < groupEnd; ++row) { |
|
|
|
// Get the multiplication results
|
|
|
|
multiplyRow(row, A, b[row], xi, yi); |
|
|
|
ValueType currentValue = xi + yi * lowerBound; |
|
|
|
// Check if the current row is better then the previously found one
|
|
|
|
if (currentValue < bestValue) { |
|
|
|
if (yBest < yi) { |
|
|
|
// We need to store the 'old' best value as it might be relevant for the decision value
|
|
|
|
xTmp[xyTmpIndex] = std::move(xBest); |
|
|
|
yTmp[xyTmpIndex] = std::move(yBest); |
|
|
|
++xyTmpIndex; |
|
|
|
} |
|
|
|
xBest = std::move(xi); |
|
|
|
yBest = std::move(yi); |
|
|
|
bestValue = std::move(currentValue); |
|
|
|
} else if (yBest > yi) { |
|
|
|
// If the value for this row is not strictly better, it might still be equal and have a better y value
|
|
|
|
if (currentValue == bestValue) { |
|
|
|
xBest = std::move(xi); |
|
|
|
yBest = std::move(yi); |
|
|
|
} else { |
|
|
|
xTmp[xyTmpIndex] = std::move(xi); |
|
|
|
yTmp[xyTmpIndex] = std::move(yi); |
|
|
|
++xyTmpIndex; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
for (;row < groupEnd; ++row) { |
|
|
|
multiplyRow(row, A, b[row], xi, yi); |
|
|
|
// Update the best choice
|
|
|
|
if (yi > yBest || (yi == yBest && xi < xBest)) { |
|
|
|
xTmp[xyTmpIndex] = std::move(xBest); |
|
|
|
yTmp[xyTmpIndex] = std::move(yBest); |
|
|
|
++xyTmpIndex; |
|
|
|
xBest = std::move(xi); |
|
|
|
yBest = std::move(yi); |
|
|
|
} else { |
|
|
|
xTmp[xyTmpIndex] = std::move(xi); |
|
|
|
yTmp[xyTmpIndex] = std::move(yi); |
|
|
|
++xyTmpIndex; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Update the decision value
|
|
|
|
for (uint64_t i = 0; i < xyTmpIndex; ++i) { |
|
|
|
ValueType deltaY = yBest - yTmp[i]; |
|
|
|
if (deltaY > storm::utility::zero<ValueType>()) { |
|
|
|
ValueType newDecisionValue = (xTmp[i] - xBest) / deltaY; |
|
|
|
if (!hasDecisionValue || newDecisionValue < decisionValue) { |
|
|
|
decisionValue = std::move(newDecisionValue); |
|
|
|
hasDecisionValue = true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
*xIt = std::move(xBest); |
|
|
|
*yIt = std::move(yBest); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bool checkRestartCriterion() { |
|
|
|
return false; |
|
|
|
// iterations <= restartMaxIterations && (minimize(dir) ? restartThreshold * improvedPrimaryBound > primaryBound : restartThreshold * primaryBound > improvedPrimaryBound
|
|
|
@ -1249,13 +1006,13 @@ namespace storm { |
|
|
|
|
|
|
|
while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { |
|
|
|
if (minimize(dir)) { |
|
|
|
helper.template performIterationStepMin(*this->A, b); |
|
|
|
helper.template performIterationStep<OptimizationDirection::Minimize>(*this->A, b); |
|
|
|
if (helper.template checkConvergenceUpdateBounds<OptimizationDirection::Minimize>(iterations, relevantValuesPtr)) { |
|
|
|
status = SolverStatus::Converged; |
|
|
|
} |
|
|
|
} else { |
|
|
|
assert(maximize(dir)); |
|
|
|
helper.template performIterationStepMax(*this->A, b); |
|
|
|
helper.template performIterationStep<OptimizationDirection::Maximize>(*this->A, b); |
|
|
|
if (helper.template checkConvergenceUpdateBounds<OptimizationDirection::Maximize>(iterations, relevantValuesPtr)) { |
|
|
|
status = SolverStatus::Converged; |
|
|
|
} |
|
|
@ -1279,6 +1036,8 @@ namespace storm { |
|
|
|
|
|
|
|
reportStatus(status, iterations); |
|
|
|
|
|
|
|
this->overallPerformedIterations += iterations; |
|
|
|
|
|
|
|
if (!this->isCachingEnabled()) { |
|
|
|
clearCache(); |
|
|
|
} |
|
|
|