|
|
@ -25,6 +25,8 @@ |
|
|
|
#include "storm/settings/SettingsManager.h"
|
|
|
|
#include "storm/settings/modules/MinMaxEquationSolverSettings.h"
|
|
|
|
|
|
|
|
#include "storm/utility/Stopwatch.h"
|
|
|
|
|
|
|
|
#include "storm/exceptions/InvalidStateException.h"
|
|
|
|
#include "storm/exceptions/InvalidPropertyException.h"
|
|
|
|
#include "storm/exceptions/InvalidSettingsException.h"
|
|
|
@ -78,6 +80,7 @@ namespace storm { |
|
|
|
|
|
|
|
template<typename ValueType> |
|
|
|
std::map<storm::storage::sparse::state_type, ValueType> SparseMdpPrctlHelper<ValueType>::computeRewardBoundedValues(OptimizationDirection dir, storm::modelchecker::multiobjective::MultiDimensionalRewardUnfolding<ValueType, true>& rewardUnfolding, storm::storage::BitVector const& initialStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory, boost::optional<ValueType> const& upperBound) { |
|
|
|
storm::utility::Stopwatch swAll(true), swBuild, swCheck; |
|
|
|
auto initEpoch = rewardUnfolding.getStartEpoch(); |
|
|
|
auto epochOrder = rewardUnfolding.getEpochComputationOrder(initEpoch); |
|
|
|
|
|
|
@ -85,47 +88,88 @@ namespace storm { |
|
|
|
std::vector<ValueType> x, b; |
|
|
|
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> minMaxSolver; |
|
|
|
for (auto const& epoch : epochOrder) { |
|
|
|
// Update some data for the case that the Matrix has changed
|
|
|
|
swBuild.start(); |
|
|
|
auto& epochModel = rewardUnfolding.setCurrentEpoch(epoch); |
|
|
|
if (epochModel.epochMatrixChanged) { |
|
|
|
x.assign(epochModel.epochMatrix.getRowGroupCount(), storm::utility::zero<ValueType>()); |
|
|
|
minMaxSolver = minMaxLinearEquationSolverFactory.create(epochModel.epochMatrix); |
|
|
|
minMaxSolver->setOptimizationDirection(dir); |
|
|
|
minMaxSolver->setCachingEnabled(true); |
|
|
|
minMaxSolver->setTrackScheduler(true); |
|
|
|
auto req = minMaxSolver->getRequirements(storm::solver::EquationSystemType::StochasticShortestPath, dir); |
|
|
|
minMaxSolver->setLowerBound(storm::utility::zero<ValueType>()); |
|
|
|
req.clearLowerBounds(); |
|
|
|
if (upperBound) { |
|
|
|
minMaxSolver->setUpperBound(upperBound.get()); |
|
|
|
req.clearUpperBounds(); |
|
|
|
swBuild.stop(); swCheck.start(); |
|
|
|
// If the epoch matrix is empty we do not need to solve a linear equation system
|
|
|
|
if (epochModel.epochMatrix.getEntryCount() == 0) { |
|
|
|
std::vector<ValueType> epochResult; |
|
|
|
epochResult.reserve(epochModel.epochInStates.getNumberOfSetBits()); |
|
|
|
|
|
|
|
auto stepSolutionIt = epochModel.stepSolutions.begin(); |
|
|
|
auto stepChoiceIt = epochModel.stepChoices.begin(); |
|
|
|
for (auto const& state : epochModel.epochInStates) { |
|
|
|
// Obtain the best choice for this state
|
|
|
|
ValueType bestValue; |
|
|
|
uint64_t lastChoice = epochModel.epochMatrix.getRowGroupIndices()[state + 1]; |
|
|
|
bool isFirstChoice = true; |
|
|
|
for (uint64_t choice = epochModel.epochMatrix.getRowGroupIndices()[state]; choice < lastChoice; ++choice) { |
|
|
|
while (*stepChoiceIt < choice) { |
|
|
|
++stepChoiceIt; |
|
|
|
++stepSolutionIt; |
|
|
|
} |
|
|
|
|
|
|
|
ValueType choiceValue = storm::utility::zero<ValueType>(); |
|
|
|
if (epochModel.objectiveRewardFilter.front().get(choice)) { |
|
|
|
choiceValue += epochModel.objectiveRewards.front()[choice]; |
|
|
|
} |
|
|
|
if (*stepChoiceIt == choice) { |
|
|
|
choiceValue += *stepSolutionIt; |
|
|
|
} |
|
|
|
|
|
|
|
if (isFirstChoice || choiceValue > bestValue) { |
|
|
|
bestValue = std::move(choiceValue); |
|
|
|
isFirstChoice = false; |
|
|
|
} |
|
|
|
} |
|
|
|
// Insert the solution w.r.t. this choice
|
|
|
|
epochResult.push_back(std::move(bestValue)); |
|
|
|
} |
|
|
|
req.clearNoEndComponents(); |
|
|
|
STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "A solver requirement is not satisfied."); |
|
|
|
minMaxSolver->setRequirementsChecked(); |
|
|
|
|
|
|
|
rewardUnfolding.setSolutionForCurrentEpoch(std::move(epochResult)); |
|
|
|
} else { |
|
|
|
auto choicesTmp = minMaxSolver->getSchedulerChoices(); |
|
|
|
minMaxSolver->setInitialScheduler(std::move(choicesTmp)); |
|
|
|
} |
|
|
|
|
|
|
|
// Prepare the right hand side of the equation system
|
|
|
|
b.assign(epochModel.epochMatrix.getRowCount(), storm::utility::zero<ValueType>()); |
|
|
|
std::vector<ValueType> const& objectiveValues = epochModel.objectiveRewards.front(); |
|
|
|
for (auto const& choice : epochModel.objectiveRewardFilter.front()) { |
|
|
|
b[choice] = objectiveValues[choice]; |
|
|
|
} |
|
|
|
auto stepSolutionIt = epochModel.stepSolutions.begin(); |
|
|
|
for (auto const& choice : epochModel.stepChoices) { |
|
|
|
b[choice] += *stepSolutionIt; |
|
|
|
++stepSolutionIt; |
|
|
|
// Update some data for the case that the Matrix has changed
|
|
|
|
if (epochModel.epochMatrixChanged) { |
|
|
|
x.assign(epochModel.epochMatrix.getRowGroupCount(), storm::utility::zero<ValueType>()); |
|
|
|
minMaxSolver = minMaxLinearEquationSolverFactory.create(epochModel.epochMatrix); |
|
|
|
minMaxSolver->setOptimizationDirection(dir); |
|
|
|
minMaxSolver->setCachingEnabled(true); |
|
|
|
minMaxSolver->setTrackScheduler(true); |
|
|
|
auto req = minMaxSolver->getRequirements(storm::solver::EquationSystemType::StochasticShortestPath, dir); |
|
|
|
minMaxSolver->setLowerBound(storm::utility::zero<ValueType>()); |
|
|
|
req.clearLowerBounds(); |
|
|
|
if (upperBound) { |
|
|
|
minMaxSolver->setUpperBound(upperBound.get()); |
|
|
|
req.clearUpperBounds(); |
|
|
|
} |
|
|
|
req.clearNoEndComponents(); |
|
|
|
STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "A solver requirement is not satisfied."); |
|
|
|
minMaxSolver->setRequirementsChecked(); |
|
|
|
} else { |
|
|
|
auto choicesTmp = minMaxSolver->getSchedulerChoices(); |
|
|
|
minMaxSolver->setInitialScheduler(std::move(choicesTmp)); |
|
|
|
} |
|
|
|
|
|
|
|
// Prepare the right hand side of the equation system
|
|
|
|
b.assign(epochModel.epochMatrix.getRowCount(), storm::utility::zero<ValueType>()); |
|
|
|
std::vector<ValueType> const& objectiveValues = epochModel.objectiveRewards.front(); |
|
|
|
for (auto const& choice : epochModel.objectiveRewardFilter.front()) { |
|
|
|
b[choice] = objectiveValues[choice]; |
|
|
|
} |
|
|
|
auto stepSolutionIt = epochModel.stepSolutions.begin(); |
|
|
|
for (auto const& choice : epochModel.stepChoices) { |
|
|
|
b[choice] += *stepSolutionIt; |
|
|
|
++stepSolutionIt; |
|
|
|
} |
|
|
|
assert(stepSolutionIt == epochModel.stepSolutions.end()); |
|
|
|
|
|
|
|
// Solve the minMax equation system
|
|
|
|
minMaxSolver->solveEquations(x, b); |
|
|
|
|
|
|
|
// Plug in the result into the reward unfolding
|
|
|
|
rewardUnfolding.setSolutionForCurrentEpoch(storm::utility::vector::filterVector(x, epochModel.epochInStates)); |
|
|
|
} |
|
|
|
assert(stepSolutionIt == epochModel.stepSolutions.end()); |
|
|
|
|
|
|
|
// Solve the minMax equation system
|
|
|
|
minMaxSolver->solveEquations(x, b); |
|
|
|
|
|
|
|
// Plug in the result into the reward unfolding
|
|
|
|
rewardUnfolding.setSolutionForCurrentEpoch(storm::utility::vector::filterVector(x, epochModel.epochInStates)); |
|
|
|
swCheck.stop(); |
|
|
|
} |
|
|
|
|
|
|
|
std::map<storm::storage::sparse::state_type, ValueType> result; |
|
|
@ -133,6 +177,16 @@ namespace storm { |
|
|
|
result[initState] = rewardUnfolding.getInitialStateResult(initEpoch, initState); |
|
|
|
} |
|
|
|
|
|
|
|
swAll.stop(); |
|
|
|
std::cout << "---------------------------------" << std::endl; |
|
|
|
std::cout << "Statistics:" << std::endl; |
|
|
|
std::cout << "---------------------------------" << std::endl; |
|
|
|
std::cout << " #checked epochs: " << epochOrder.size() << "." << std::endl; |
|
|
|
std::cout << " overall Time: " << swAll << "." << std::endl; |
|
|
|
std::cout << "Epoch Model building Time: " << swBuild << "." << std::endl; |
|
|
|
std::cout << "Epoch Model checking Time: " << swBuild << "." << std::endl; |
|
|
|
std::cout << "---------------------------------" << std::endl; |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|