Browse Source

towards bounded reachability: added the ability to have a lower/upper bound for the weightVectorChecker result

Former-commit-id: 413c2dee0a
tempestpy_adaptions
TimQu 9 years ago
parent
commit
75dd78ebec
  1. 21
      src/modelchecker/multiobjective/helper/SparseMaMultiObjectiveWeightVectorChecker.cpp
  2. 10
      src/modelchecker/multiobjective/helper/SparseMdpMultiObjectiveWeightVectorChecker.cpp
  3. 80
      src/modelchecker/multiobjective/helper/SparseMultiObjectiveHelper.cpp
  4. 4
      src/modelchecker/multiobjective/helper/SparseMultiObjectiveHelper.h
  5. 4
      src/modelchecker/multiobjective/helper/SparseMultiObjectivePostprocessor.cpp
  6. 19
      src/modelchecker/multiobjective/helper/SparseMultiObjectiveRefinementStep.h
  7. 51
      src/modelchecker/multiobjective/helper/SparseMultiObjectiveWeightVectorChecker.cpp
  8. 38
      src/modelchecker/multiobjective/helper/SparseMultiObjectiveWeightVectorChecker.h
  9. 2
      src/modelchecker/results/ParetoCurveCheckResult.cpp

21
src/modelchecker/multiobjective/helper/SparseMaMultiObjectiveWeightVectorChecker.cpp

@ -16,12 +16,12 @@ namespace storm {
// Set the (discretized) state action rewards. // Set the (discretized) state action rewards.
this->discreteActionRewards.resize(data.objectives.size()); this->discreteActionRewards.resize(data.objectives.size());
for(auto objIndex : this->unboundedObjectives) { for(auto objIndex : this->unboundedObjectives) {
STORM_LOG_ASSERT(!this->data.preprocessedModel.getRewardModel(this->data.objectives[objIndex].rewardModelName).hasTransitionRewards(), "Preprocessed Reward model has transition rewards which is not expected.");
this->discreteActionRewards[objIndex] = this->data.preprocessedModel.getRewardModel(this->data.objectives[objIndex].rewardModelName).getStateActionRewardVector();
if(this->data.preprocessedModel.getRewardModel(this->data.objectives[objIndex].rewardModelName).hasStateRewards()) {
auto const& stateRewards = this->data.preprocessedModel.getRewardModel(this->data.objectives[objIndex].rewardModelName).getStateRewardVector();
typename SparseMaModelType::RewardModelType const& rewModel = this->data.preprocessedModel.getRewardModel(this->data.objectives[objIndex].rewardModelName);
STORM_LOG_ASSERT(!rewModel.hasTransitionRewards(), "Preprocessed Reward model has transition rewards which is not expected.");
this->discreteActionRewards[objIndex] = rewModel.hasStateActionRewards() ? rewModel.getStateActionRewardVector() : std::vector<ValueType>(this->data.preprocessedModel.getTransitionMatrix().getRowCount(), storm::utility::zero<ValueType>());
if(rewModel.hasStateRewards()) {
for(auto markovianState : this->data.getMarkovianStatesOfPreprocessedModel()) { for(auto markovianState : this->data.getMarkovianStatesOfPreprocessedModel()) {
this->discreteActionRewards[objIndex][this->data.preprocessedModel.getTransitionMatrix().getRowGroupIndices()[markovianState]] += stateRewards[markovianState] / this->data.preprocessedModel.getExitRate(markovianState);
this->discreteActionRewards[objIndex][this->data.preprocessedModel.getTransitionMatrix().getRowGroupIndices()[markovianState]] += rewModel.getStateReward(markovianState) / this->data.preprocessedModel.getExitRate(markovianState);
} }
} }
@ -31,7 +31,7 @@ namespace storm {
template <class SparseMaModelType> template <class SparseMaModelType>
void SparseMaMultiObjectiveWeightVectorChecker<SparseMaModelType>::boundedPhase(std::vector<ValueType> const& weightVector, std::vector<ValueType>& weightedRewardVector) { void SparseMaMultiObjectiveWeightVectorChecker<SparseMaModelType>::boundedPhase(std::vector<ValueType> const& weightVector, std::vector<ValueType>& weightedRewardVector) {
STORM_LOG_ERROR("BOUNDED OBJECTIVES FOR MARKOV AUTOMATA NOT YET IMPLEMENTED"); STORM_LOG_ERROR("BOUNDED OBJECTIVES FOR MARKOV AUTOMATA NOT YET IMPLEMENTED");
/*
/*
// Allocate some memory so this does not need to happen for each time epoch // Allocate some memory so this does not need to happen for each time epoch
std::vector<uint_fast64_t> optimalChoicesInCurrentEpoch(this->data.preprocessedModel.getNumberOfStates()); std::vector<uint_fast64_t> optimalChoicesInCurrentEpoch(this->data.preprocessedModel.getNumberOfStates());
std::vector<ValueType> choiceValues(weightedRewardVector.size()); std::vector<ValueType> choiceValues(weightedRewardVector.size());
@ -43,6 +43,9 @@ namespace storm {
uint_fast64_t timeBound = boost::get<uint_fast64_t>(this->data.objectives[objIndex].timeBounds.get()); uint_fast64_t timeBound = boost::get<uint_fast64_t>(this->data.objectives[objIndex].timeBounds.get());
auto timeBoundIt = timeBounds.insert(std::make_pair(timeBound, storm::storage::BitVector(this->data.objectives.size(), false))).first; auto timeBoundIt = timeBounds.insert(std::make_pair(timeBound, storm::storage::BitVector(this->data.objectives.size(), false))).first;
timeBoundIt->second.set(objIndex); timeBoundIt->second.set(objIndex);
// There is no error for the values of these objectives.
this->offsetsToLowerBound[objIndex] = storm::utility::zero<ValueType>();
this->offsetsToUpperBound[objIndex] = storm::utility::zero<ValueType>();
} }
storm::storage::BitVector objectivesAtCurrentEpoch = this->unboundedObjectives; storm::storage::BitVector objectivesAtCurrentEpoch = this->unboundedObjectives;
auto timeBoundIt = timeBounds.begin(); auto timeBoundIt = timeBounds.begin();
@ -64,7 +67,7 @@ namespace storm {
// TODO we could compute the result for one of the objectives from the weighted result, the given weight vector, and the remaining objective results. // TODO we could compute the result for one of the objectives from the weighted result, the given weight vector, and the remaining objective results.
for(auto objIndex : objectivesAtCurrentEpoch) { for(auto objIndex : objectivesAtCurrentEpoch) {
std::vector<ValueType>& objectiveResult = this->objectiveResults[objIndex]; std::vector<ValueType>& objectiveResult = this->objectiveResults[objIndex];
std::vector<ValueType> objectiveRewards = getObjectiveRewardAsDiscreteActionRewards(objIndex);
std::vector<ValueType> objectiveRewards = this->discreteActionRewards[objIndex];
auto rowGroupIndexIt = this->data.preprocessedModel.getTransitionMatrix().getRowGroupIndices().begin(); auto rowGroupIndexIt = this->data.preprocessedModel.getTransitionMatrix().getRowGroupIndices().begin();
auto optimalChoiceIt = optimalChoicesInCurrentEpoch.begin(); auto optimalChoiceIt = optimalChoicesInCurrentEpoch.begin();
for(ValueType& stateValue : temporaryResult){ for(ValueType& stateValue : temporaryResult){
@ -79,9 +82,9 @@ namespace storm {
objectiveResult.swap(temporaryResult); objectiveResult.swap(temporaryResult);
} }
} }
*/
*/
} }
template class SparseMaMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>; template class SparseMaMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>;
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template class SparseMaMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>; template class SparseMaMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>;

10
src/modelchecker/multiobjective/helper/SparseMdpMultiObjectiveWeightVectorChecker.cpp

@ -14,9 +14,10 @@ namespace storm {
template <class SparseMdpModelType> template <class SparseMdpModelType>
SparseMdpMultiObjectiveWeightVectorChecker<SparseMdpModelType>::SparseMdpMultiObjectiveWeightVectorChecker(PreprocessorData const& data) : SparseMultiObjectiveWeightVectorChecker<SparseMdpModelType>(data) { SparseMdpMultiObjectiveWeightVectorChecker<SparseMdpModelType>::SparseMdpMultiObjectiveWeightVectorChecker(PreprocessorData const& data) : SparseMultiObjectiveWeightVectorChecker<SparseMdpModelType>(data) {
// set the state action rewards // set the state action rewards
for(uint_fast64_t objIndex = 0; objIndex < data.objectives.size(); ++objIndex) {
STORM_LOG_ASSERT(!this->data.preprocessedModel.getRewardModel(this->data.objectives[objIndex].rewardModelName).hasTransitionRewards(), "Reward model has transition rewards which is not expected.");
this->discreteActionRewards[objIndex] = this->data.preprocessedModel.getRewardModel(this->data.objectives[objIndex].rewardModelName).getTotalRewardVector(this->data.preprocessedModel.getTransitionMatrix());
for(uint_fast64_t objIndex = 0; objIndex < this->data.objectives.size(); ++objIndex) {
typename SparseMdpModelType::RewardModelType const& rewModel = this->data.preprocessedModel.getRewardModel(this->data.objectives[objIndex].rewardModelName);
STORM_LOG_ASSERT(!rewModel.hasTransitionRewards(), "Reward model has transition rewards which is not expected.");
this->discreteActionRewards[objIndex] = rewModel.getTotalRewardVector(this->data.preprocessedModel.getTransitionMatrix());
} }
} }
@ -33,6 +34,9 @@ namespace storm {
uint_fast64_t timeBound = boost::get<uint_fast64_t>(this->data.objectives[objIndex].timeBounds.get()); uint_fast64_t timeBound = boost::get<uint_fast64_t>(this->data.objectives[objIndex].timeBounds.get());
auto timeBoundIt = timeBounds.insert(std::make_pair(timeBound, storm::storage::BitVector(this->data.objectives.size(), false))).first; auto timeBoundIt = timeBounds.insert(std::make_pair(timeBound, storm::storage::BitVector(this->data.objectives.size(), false))).first;
timeBoundIt->second.set(objIndex); timeBoundIt->second.set(objIndex);
// There is no error for the values of these objectives.
this->offsetsToLowerBound[objIndex] = storm::utility::zero<ValueType>();
this->offsetsToUpperBound[objIndex] = storm::utility::zero<ValueType>();
} }
storm::storage::BitVector objectivesAtCurrentEpoch = this->unboundedObjectives; storm::storage::BitVector objectivesAtCurrentEpoch = this->unboundedObjectives;
auto timeBoundIt = timeBounds.begin(); auto timeBoundIt = timeBounds.begin();

80
src/modelchecker/multiobjective/helper/SparseMultiObjectiveHelper.cpp

@ -9,6 +9,7 @@
#include "src/utility/vector.h" #include "src/utility/vector.h"
#include "src/settings//SettingsManager.h" #include "src/settings//SettingsManager.h"
#include "src/settings/modules/MultiObjectiveSettings.h" #include "src/settings/modules/MultiObjectiveSettings.h"
#include "src/settings/modules/GeneralSettings.h"
#include "src/exceptions/UnexpectedException.h" #include "src/exceptions/UnexpectedException.h"
@ -22,7 +23,6 @@ namespace storm {
ResultData resultData; ResultData resultData;
resultData.overApproximation() = storm::storage::geometry::Polytope<RationalNumberType>::createUniversalPolytope(); resultData.overApproximation() = storm::storage::geometry::Polytope<RationalNumberType>::createUniversalPolytope();
resultData.underApproximation() = storm::storage::geometry::Polytope<RationalNumberType>::createEmptyPolytope(); resultData.underApproximation() = storm::storage::geometry::Polytope<RationalNumberType>::createEmptyPolytope();
if(!checkIfPreprocessingWasConclusive(preprocessorData)) { if(!checkIfPreprocessingWasConclusive(preprocessorData)) {
switch(preprocessorData.queryType) { switch(preprocessorData.queryType) {
case PreprocessorData::QueryType::Achievability: case PreprocessorData::QueryType::Achievability:
@ -57,6 +57,9 @@ namespace storm {
template <class SparseModelType, typename RationalNumberType> template <class SparseModelType, typename RationalNumberType>
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::achievabilityQuery(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker, ResultData& resultData) { void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::achievabilityQuery(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker, ResultData& resultData) {
//Set the maximum gap between lower and upper bound of the weightVectorChecker result we initially allow for this query type.
weightVectorChecker->setMaximumLowerUpperBoundGap(storm::utility::convertNumber<SparseModelValueType>(0.1)); // TODO try other values?
// Get a point that represents the thresholds
Point thresholds; Point thresholds;
thresholds.reserve(preprocessorData.objectives.size()); thresholds.reserve(preprocessorData.objectives.size());
storm::storage::BitVector strictThresholds(preprocessorData.objectives.size()); storm::storage::BitVector strictThresholds(preprocessorData.objectives.size());
@ -64,11 +67,11 @@ namespace storm {
thresholds.push_back(storm::utility::convertNumber<RationalNumberType>(*preprocessorData.objectives[objIndex].threshold)); thresholds.push_back(storm::utility::convertNumber<RationalNumberType>(*preprocessorData.objectives[objIndex].threshold));
strictThresholds.set(objIndex, preprocessorData.objectives[objIndex].thresholdIsStrict); strictThresholds.set(objIndex, preprocessorData.objectives[objIndex].thresholdIsStrict);
} }
// repeatedly refine the over/ under approximation until the threshold point is either in the under approx. or not in the over approx.
storm::storage::BitVector individualObjectivesToBeChecked(preprocessorData.objectives.size(), true); storm::storage::BitVector individualObjectivesToBeChecked(preprocessorData.objectives.size(), true);
do { do {
WeightVector separatingVector = findSeparatingVector(thresholds, resultData.underApproximation(), individualObjectivesToBeChecked); WeightVector separatingVector = findSeparatingVector(thresholds, resultData.underApproximation(), individualObjectivesToBeChecked);
performRefinementStep(separatingVector, preprocessorData.produceSchedulers, weightVectorChecker, resultData);
performRefinementStep(std::move(separatingVector), preprocessorData.produceSchedulers, weightVectorChecker, resultData);
if(!checkIfThresholdsAreSatisfied(resultData.overApproximation(), thresholds, strictThresholds)){ if(!checkIfThresholdsAreSatisfied(resultData.overApproximation(), thresholds, strictThresholds)){
resultData.setThresholdsAreAchievable(false); resultData.setThresholdsAreAchievable(false);
} }
@ -81,6 +84,9 @@ namespace storm {
template <class SparseModelType, typename RationalNumberType> template <class SparseModelType, typename RationalNumberType>
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::numericalQuery(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker, ResultData& resultData) { void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::numericalQuery(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker, ResultData& resultData) {
STORM_LOG_ASSERT(preprocessorData.indexOfOptimizingObjective, "Detected numerical query but index of optimizing objective is not set."); STORM_LOG_ASSERT(preprocessorData.indexOfOptimizingObjective, "Detected numerical query but index of optimizing objective is not set.");
// Set the maximum gap between lower and upper bound of the weightVectorChecker result we initially allow for this query type.
weightVectorChecker->setMaximumLowerUpperBoundGap(storm::utility::convertNumber<SparseModelValueType>(0.1)); // TODO try other values?
// initialize some data
uint_fast64_t optimizingObjIndex = *preprocessorData.indexOfOptimizingObjective; uint_fast64_t optimizingObjIndex = *preprocessorData.indexOfOptimizingObjective;
Point thresholds; Point thresholds;
thresholds.reserve(preprocessorData.objectives.size()); thresholds.reserve(preprocessorData.objectives.size());
@ -108,9 +114,9 @@ namespace storm {
individualObjectivesToBeChecked.set(optimizingObjIndex, false); individualObjectivesToBeChecked.set(optimizingObjIndex, false);
do { do {
WeightVector separatingVector = findSeparatingVector(thresholds, resultData.underApproximation(), individualObjectivesToBeChecked); WeightVector separatingVector = findSeparatingVector(thresholds, resultData.underApproximation(), individualObjectivesToBeChecked);
performRefinementStep(separatingVector, preprocessorData.produceSchedulers, weightVectorChecker, resultData);
performRefinementStep(std::move(separatingVector), preprocessorData.produceSchedulers, weightVectorChecker, resultData);
//Pick the threshold for the optimizing objective low enough so valid solutions are not excluded //Pick the threshold for the optimizing objective low enough so valid solutions are not excluded
thresholds[optimizingObjIndex] = std::min(thresholds[optimizingObjIndex], resultData.refinementSteps().back().getPoint()[optimizingObjIndex]);
thresholds[optimizingObjIndex] = std::min(thresholds[optimizingObjIndex], resultData.refinementSteps().back().getLowerBoundPoint()[optimizingObjIndex]);
if(!checkIfThresholdsAreSatisfied(resultData.overApproximation(), thresholds, strictThresholds)){ if(!checkIfThresholdsAreSatisfied(resultData.overApproximation(), thresholds, strictThresholds)){
resultData.setThresholdsAreAchievable(false); resultData.setThresholdsAreAchievable(false);
} }
@ -125,6 +131,11 @@ namespace storm {
// Note that we do not have to care whether a threshold is strict anymore, because the resulting optimum should be // Note that we do not have to care whether a threshold is strict anymore, because the resulting optimum should be
// the supremum over all strategies. Hence, one could combine a scheduler inducing the optimum value (but possibly violating strict // the supremum over all strategies. Hence, one could combine a scheduler inducing the optimum value (but possibly violating strict
// thresholds) and (with very low probability) a scheduler that satisfies all (possibly strict) thresholds. // thresholds) and (with very low probability) a scheduler that satisfies all (possibly strict) thresholds.
// The euclidean distance between the lower and upper bounds of the results of the weightVectorChecker should be less than the precision given in the settings
SparseModelValueType gap = storm::utility::convertNumber<SparseModelValueType>(storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>().getPrecision());
gap -= storm::utility::convertNumber<SparseModelValueType>(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getPrecision());
gap /= storm::utility::sqrt(static_cast<SparseModelValueType>(preprocessorData.objectives.size()));
weightVectorChecker->setMaximumLowerUpperBoundGap(gap); // TODO try other values?
while(true) { while(true) {
std::pair<Point, bool> optimizationRes = resultData.underApproximation()->intersection(thresholdsAsPolytope)->optimize(directionOfOptimizingObjective); std::pair<Point, bool> optimizationRes = resultData.underApproximation()->intersection(thresholdsAsPolytope)->optimize(directionOfOptimizingObjective);
STORM_LOG_THROW(optimizationRes.second, storm::exceptions::UnexpectedException, "The underapproximation is either unbounded or empty."); STORM_LOG_THROW(optimizationRes.second, storm::exceptions::UnexpectedException, "The underapproximation is either unbounded or empty.");
@ -142,18 +153,25 @@ namespace storm {
break; break;
} }
WeightVector separatingVector = findSeparatingVector(thresholds, resultData.underApproximation(), individualObjectivesToBeChecked); WeightVector separatingVector = findSeparatingVector(thresholds, resultData.underApproximation(), individualObjectivesToBeChecked);
performRefinementStep(separatingVector, preprocessorData.produceSchedulers, weightVectorChecker, resultData);
performRefinementStep(std::move(separatingVector), preprocessorData.produceSchedulers, weightVectorChecker, resultData);
} }
} }
} }
template <class SparseModelType, typename RationalNumberType> template <class SparseModelType, typename RationalNumberType>
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::paretoQuery(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker, ResultData& resultData) { void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::paretoQuery(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker, ResultData& resultData) {
// Set the maximum gap between lower and upper bound of the weightVectorChecker result we initially allow for this query type.
// The euclidean distance between the lower and upper bounds of the results of the weightVectorChecker should be less than the precision given in the settings
SparseModelValueType gap = storm::utility::convertNumber<SparseModelValueType>(storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>().getPrecision());
gap -= storm::utility::convertNumber<SparseModelValueType>(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getPrecision());
gap /= storm::utility::sqrt(static_cast<SparseModelValueType>(preprocessorData.objectives.size()));
weightVectorChecker->setMaximumLowerUpperBoundGap(gap); // TODO try other values?
//First consider the objectives individually //First consider the objectives individually
for(uint_fast64_t objIndex = 0; objIndex<preprocessorData.objectives.size() && !maxStepsPerformed(resultData); ++objIndex) { for(uint_fast64_t objIndex = 0; objIndex<preprocessorData.objectives.size() && !maxStepsPerformed(resultData); ++objIndex) {
WeightVector direction(preprocessorData.objectives.size(), storm::utility::zero<RationalNumberType>()); WeightVector direction(preprocessorData.objectives.size(), storm::utility::zero<RationalNumberType>());
direction[objIndex] = storm::utility::one<RationalNumberType>(); direction[objIndex] = storm::utility::one<RationalNumberType>();
performRefinementStep(direction, preprocessorData.produceSchedulers, weightVectorChecker, resultData);
performRefinementStep(std::move(direction), preprocessorData.produceSchedulers, weightVectorChecker, resultData);
} }
while(true) { while(true) {
@ -177,7 +195,7 @@ namespace storm {
break; break;
} }
WeightVector direction = underApproxHalfspaces[farestHalfspaceIndex].normalVector(); WeightVector direction = underApproxHalfspaces[farestHalfspaceIndex].normalVector();
performRefinementStep(direction, preprocessorData.produceSchedulers, weightVectorChecker, resultData);
performRefinementStep(std::move(direction), preprocessorData.produceSchedulers, weightVectorChecker, resultData);
} }
} }
@ -225,13 +243,41 @@ namespace storm {
} }
template <class SparseModelType, typename RationalNumberType> template <class SparseModelType, typename RationalNumberType>
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::performRefinementStep(WeightVector const& direction, bool saveScheduler, WeightVectorCheckerType weightVectorChecker, ResultData& result) {
weightVectorChecker->check(storm::utility::vector::convertNumericVector<typename SparseModelType::ValueType>(direction));
STORM_LOG_DEBUG("weighted objectives checker result is " << storm::utility::vector::convertNumericVector<double>(weightVectorChecker->getInitialStateResultOfObjectives()));
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::performRefinementStep(WeightVector&& direction, bool saveScheduler, WeightVectorCheckerType weightVectorChecker, ResultData& result) {
// Normalize the direction vector so that the entries sum up to one
storm::utility::vector::scaleVectorInPlace(direction, storm::utility::one<RationalNumberType>() / std::accumulate(direction.begin(), direction.end(), storm::utility::zero<RationalNumberType>()));
// Check if we already did a refinement step with that direction vector. If this is the case, we increase the precision.
// We start with the most recent steps to consider the most recent result for this direction vector
boost::optional<SparseModelValueType> oldMaximumLowerUpperBoundGap;
for(auto stepIt = result.refinementSteps().rbegin(); stepIt != result.refinementSteps().rend(); ++stepIt) {
if(stepIt->getWeightVector() == direction) {
STORM_LOG_WARN("Performing multiple refinement steps with the same direction vector.");
oldMaximumLowerUpperBoundGap = weightVectorChecker->getMaximumLowerUpperBoundGap();
std::vector<RationalNumberType> lowerUpperDistances = stepIt->getUpperBoundPoint();
storm::utility::vector::subtractVectors(lowerUpperDistances, stepIt->getLowerBoundPoint(), lowerUpperDistances);
// shorten the distance between lower and upper bound for the new result by multiplying the current distance with 0.5
// TODO: try other values/strategies?
RationalNumberType distance = storm::utility::sqrt(storm::utility::vector::dotProduct(lowerUpperDistances, lowerUpperDistances));
weightVectorChecker->setMaximumLowerUpperBoundGap(storm::utility::convertNumber<SparseModelValueType>(distance) + storm::utility::convertNumber<SparseModelValueType>(0.5));
break;
}
}
weightVectorChecker->check(storm::utility::vector::convertNumericVector<SparseModelValueType>(direction));
if(oldMaximumLowerUpperBoundGap) {
// Reset the precision back to the previous values
weightVectorChecker->setMaximumLowerUpperBoundGap(*oldMaximumLowerUpperBoundGap);
}
STORM_LOG_DEBUG("weighted objectives checker result (lower bounds) is " << storm::utility::vector::convertNumericVector<double>(weightVectorChecker->getLowerBoundsOfInitialStateResults()));
if(saveScheduler) { if(saveScheduler) {
result.refinementSteps().emplace_back(direction, weightVectorChecker->template getInitialStateResultOfObjectives<RationalNumberType>(), weightVectorChecker->getScheduler());
result.refinementSteps().emplace_back(direction,
storm::utility::vector::convertNumericVector<RationalNumberType>(weightVectorChecker->getLowerBoundsOfInitialStateResults()),
storm::utility::vector::convertNumericVector<RationalNumberType>(weightVectorChecker->getUpperBoundsOfInitialStateResults()),
weightVectorChecker->getScheduler());
} else { } else {
result.refinementSteps().emplace_back(direction, weightVectorChecker->template getInitialStateResultOfObjectives<RationalNumberType>());
result.refinementSteps().emplace_back(direction,
storm::utility::vector::convertNumericVector<RationalNumberType>(weightVectorChecker->getLowerBoundsOfInitialStateResults()),
storm::utility::vector::convertNumericVector<RationalNumberType>(weightVectorChecker->getUpperBoundsOfInitialStateResults()));
} }
updateOverApproximation(result.refinementSteps(), result.overApproximation()); updateOverApproximation(result.refinementSteps(), result.overApproximation());
updateUnderApproximation(result.refinementSteps(), result.underApproximation()); updateUnderApproximation(result.refinementSteps(), result.underApproximation());
@ -239,18 +285,18 @@ namespace storm {
template <class SparseModelType, typename RationalNumberType> template <class SparseModelType, typename RationalNumberType>
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::updateOverApproximation(std::vector<RefinementStep> const& refinementSteps, std::shared_ptr<storm::storage::geometry::Polytope<RationalNumberType>>& overApproximation) { void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::updateOverApproximation(std::vector<RefinementStep> const& refinementSteps, std::shared_ptr<storm::storage::geometry::Polytope<RationalNumberType>>& overApproximation) {
storm::storage::geometry::Halfspace<RationalNumberType> h(refinementSteps.back().getWeightVector(), storm::utility::vector::dotProduct(refinementSteps.back().getWeightVector(), refinementSteps.back().getPoint()));
storm::storage::geometry::Halfspace<RationalNumberType> h(refinementSteps.back().getWeightVector(), storm::utility::vector::dotProduct(refinementSteps.back().getWeightVector(), refinementSteps.back().getUpperBoundPoint()));
// Due to numerical issues, it might be the case that the updated overapproximation does not contain the underapproximation, // Due to numerical issues, it might be the case that the updated overapproximation does not contain the underapproximation,
// e.g., when the new point is strictly contained in the underapproximation. Check if this is the case. // e.g., when the new point is strictly contained in the underapproximation. Check if this is the case.
RationalNumberType maximumOffset = h.offset(); RationalNumberType maximumOffset = h.offset();
for(auto const& step : refinementSteps){ for(auto const& step : refinementSteps){
maximumOffset = std::max(maximumOffset, storm::utility::vector::dotProduct(h.normalVector(), step.getPoint()));
maximumOffset = std::max(maximumOffset, storm::utility::vector::dotProduct(h.normalVector(), step.getLowerBoundPoint()));
} }
if(maximumOffset > h.offset()){ if(maximumOffset > h.offset()){
// We correct the issue by shifting the halfspace such that it contains the underapproximation // We correct the issue by shifting the halfspace such that it contains the underapproximation
h.offset() = maximumOffset; h.offset() = maximumOffset;
STORM_LOG_WARN("Numerical issues: The overapproximation would not contain the underapproximation. Hence, a halfspace is shifted by " << storm::utility::convertNumber<double>(h.euclideanDistance(refinementSteps.back().getPoint())) << ".");
STORM_LOG_WARN("Numerical issues: The overapproximation would not contain the underapproximation. Hence, a halfspace is shifted by " << storm::utility::convertNumber<double>(h.euclideanDistance(refinementSteps.back().getUpperBoundPoint())) << ".");
} }
overApproximation = overApproximation->intersection(h); overApproximation = overApproximation->intersection(h);
STORM_LOG_DEBUG("Updated OverApproximation to " << overApproximation->toString(true)); STORM_LOG_DEBUG("Updated OverApproximation to " << overApproximation->toString(true));
@ -261,7 +307,7 @@ namespace storm {
std::vector<Point> paretoPoints; std::vector<Point> paretoPoints;
paretoPoints.reserve(refinementSteps.size()); paretoPoints.reserve(refinementSteps.size());
for(auto const& step : refinementSteps) { for(auto const& step : refinementSteps) {
paretoPoints.push_back(step.getPoint());
paretoPoints.push_back(step.getLowerBoundPoint());
} }
underApproximation = storm::storage::geometry::Polytope<RationalNumberType>::createDownwardClosure(paretoPoints); underApproximation = storm::storage::geometry::Polytope<RationalNumberType>::createDownwardClosure(paretoPoints);
STORM_LOG_DEBUG("Updated UnderApproximation to " << underApproximation->toString(true)); STORM_LOG_DEBUG("Updated UnderApproximation to " << underApproximation->toString(true));

4
src/modelchecker/multiobjective/helper/SparseMultiObjectiveHelper.h

@ -16,6 +16,8 @@ namespace storm {
template <class SparseModelType, typename RationalNumberType> template <class SparseModelType, typename RationalNumberType>
class SparseMultiObjectiveHelper { class SparseMultiObjectiveHelper {
public: public:
typedef typename SparseModelType::ValueType SparseModelValueType;
typedef SparseMultiObjectivePreprocessorData<SparseModelType> PreprocessorData; typedef SparseMultiObjectivePreprocessorData<SparseModelType> PreprocessorData;
typedef SparseMultiObjectiveResultData<RationalNumberType> ResultData; typedef SparseMultiObjectiveResultData<RationalNumberType> ResultData;
typedef SparseMultiObjectiveRefinementStep<RationalNumberType> RefinementStep; typedef SparseMultiObjectiveRefinementStep<RationalNumberType> RefinementStep;
@ -52,7 +54,7 @@ namespace storm {
/* /*
* Refines the current result w.r.t. the given direction vector * Refines the current result w.r.t. the given direction vector
*/ */
static void performRefinementStep(WeightVector const& direction, bool saveScheduler, WeightVectorCheckerType weightVectorChecker, ResultData& resultData);
static void performRefinementStep(WeightVector&& direction, bool saveScheduler, WeightVectorCheckerType weightVectorChecker, ResultData& resultData);
/* /*
* Updates the overapproximation after a refinement step has been performed * Updates the overapproximation after a refinement step has been performed

4
src/modelchecker/multiobjective/helper/SparseMultiObjectivePostprocessor.cpp

@ -170,7 +170,7 @@ namespace storm {
std::vector<std::vector<ValueType>> paretoOptimalPoints; std::vector<std::vector<ValueType>> paretoOptimalPoints;
paretoOptimalPoints.reserve(resultData.refinementSteps().size()); paretoOptimalPoints.reserve(resultData.refinementSteps().size());
for(auto const& step : resultData.refinementSteps()) { for(auto const& step : resultData.refinementSteps()) {
paretoOptimalPoints.push_back(storm::utility::vector::convertNumericVector<ValueType>(transformToOriginalValues(step.getPoint(), preprocessorData)));
paretoOptimalPoints.push_back(storm::utility::vector::convertNumericVector<ValueType>(transformToOriginalValues(step.getLowerBoundPoint(), preprocessorData)));
} }
return std::unique_ptr<CheckResult>(new ParetoCurveCheckResult<ValueType>( return std::unique_ptr<CheckResult>(new ParetoCurveCheckResult<ValueType>(
initState, initState,
@ -220,7 +220,7 @@ namespace storm {
std::vector<std::vector<RationalNumberType>> paretoPoints; std::vector<std::vector<RationalNumberType>> paretoPoints;
paretoPoints.reserve(resultData.refinementSteps().size()); paretoPoints.reserve(resultData.refinementSteps().size());
for(auto const& step : resultData.refinementSteps()) { for(auto const& step : resultData.refinementSteps()) {
paretoPoints.push_back(transformToOriginalValues(step.getPoint(), preprocessorData));
paretoPoints.push_back(transformToOriginalValues(step.getLowerBoundPoint(), preprocessorData));
boundaries.enlarge(paretoPoints.back()); boundaries.enlarge(paretoPoints.back());
} }
auto underApproxVertices = transformedUnderApprox->getVertices(); auto underApproxVertices = transformedUnderApprox->getVertices();

19
src/modelchecker/multiobjective/helper/SparseMultiObjectiveRefinementStep.h

@ -14,19 +14,19 @@ namespace storm {
class SparseMultiObjectiveRefinementStep { class SparseMultiObjectiveRefinementStep {
public: public:
SparseMultiObjectiveRefinementStep(std::vector<RationalNumberType> const& weightVector, std::vector<RationalNumberType> const& point, storm::storage::TotalScheduler const& scheduler) : weightVector(weightVector), point(point), scheduler(scheduler) {
SparseMultiObjectiveRefinementStep(std::vector<RationalNumberType> const& weightVector, std::vector<RationalNumberType> const& lowerBoundPoint, std::vector<RationalNumberType> const& upperBoundPoint, storm::storage::TotalScheduler const& scheduler) : weightVector(weightVector), lowerBoundPoint(lowerBoundPoint), upperBoundPoint(upperBoundPoint), scheduler(scheduler) {
//Intentionally left empty //Intentionally left empty
} }
SparseMultiObjectiveRefinementStep(std::vector<RationalNumberType>&& weightVector, std::vector<RationalNumberType>&& point, storm::storage::TotalScheduler&& scheduler) : weightVector(weightVector), point(point), scheduler(scheduler) {
SparseMultiObjectiveRefinementStep(std::vector<RationalNumberType>&& weightVector, std::vector<RationalNumberType>&& lowerBoundPoint, std::vector<RationalNumberType>&& upperBoundPoint, storm::storage::TotalScheduler&& scheduler) : weightVector(weightVector), lowerBoundPoint(lowerBoundPoint), upperBoundPoint(upperBoundPoint), scheduler(scheduler) {
//Intentionally left empty //Intentionally left empty
} }
SparseMultiObjectiveRefinementStep(std::vector<RationalNumberType> const& weightVector, std::vector<RationalNumberType> const& point) : weightVector(weightVector), point(point) {
SparseMultiObjectiveRefinementStep(std::vector<RationalNumberType> const& weightVector, std::vector<RationalNumberType> const& lowerBoundPoint, std::vector<RationalNumberType> const& upperBoundPoint) : weightVector(weightVector), lowerBoundPoint(lowerBoundPoint), upperBoundPoint(upperBoundPoint) {
//Intentionally left empty //Intentionally left empty
} }
SparseMultiObjectiveRefinementStep(std::vector<RationalNumberType>&& weightVector, std::vector<RationalNumberType>&& point) : weightVector(weightVector), point(point) {
SparseMultiObjectiveRefinementStep(std::vector<RationalNumberType>&& weightVector, std::vector<RationalNumberType>&& lowerBoundPoint, std::vector<RationalNumberType>&& upperBoundPoint) : weightVector(weightVector), lowerBoundPoint(lowerBoundPoint), upperBoundPoint(upperBoundPoint) {
//Intentionally left empty //Intentionally left empty
} }
@ -34,8 +34,12 @@ namespace storm {
return weightVector; return weightVector;
} }
std::vector<RationalNumberType> const& getPoint() const {
return point;
std::vector<RationalNumberType> const& getLowerBoundPoint() const {
return lowerBoundPoint;
}
std::vector<RationalNumberType> const& getUpperBoundPoint() const {
return upperBoundPoint;
} }
bool hasScheduler() const { bool hasScheduler() const {
@ -48,7 +52,8 @@ namespace storm {
private: private:
std::vector<RationalNumberType> const weightVector; std::vector<RationalNumberType> const weightVector;
std::vector<RationalNumberType> const point;
std::vector<RationalNumberType> const lowerBoundPoint;
std::vector<RationalNumberType> const upperBoundPoint;
boost::optional<storm::storage::TotalScheduler> const scheduler; boost::optional<storm::storage::TotalScheduler> const scheduler;
}; };
} }

51
src/modelchecker/multiobjective/helper/SparseMultiObjectiveWeightVectorChecker.cpp

@ -22,7 +22,7 @@ namespace storm {
template <class SparseModelType> template <class SparseModelType>
SparseMultiObjectiveWeightVectorChecker<SparseModelType>::SparseMultiObjectiveWeightVectorChecker(PreprocessorData const& data) : data(data), unboundedObjectives(data.objectives.size()), discreteActionRewards(data.objectives.size()), checkHasBeenCalled(false), objectiveResults(data.objectives.size()){
SparseMultiObjectiveWeightVectorChecker<SparseModelType>::SparseMultiObjectiveWeightVectorChecker(PreprocessorData const& data) : data(data), unboundedObjectives(data.objectives.size()), discreteActionRewards(data.objectives.size()), checkHasBeenCalled(false), objectiveResults(data.objectives.size()), offsetsToLowerBound(data.objectives.size()), offsetsToUpperBound(data.objectives.size()) {
// set the unbounded objectives // set the unbounded objectives
for(uint_fast64_t objIndex = 0; objIndex < data.objectives.size(); ++objIndex) { for(uint_fast64_t objIndex = 0; objIndex < data.objectives.size(); ++objIndex) {
@ -44,22 +44,42 @@ namespace storm {
unboundedWeightedPhase(weightedRewardVector); unboundedWeightedPhase(weightedRewardVector);
STORM_LOG_DEBUG("Unbounded weighted phase result: " << weightedResult[data.preprocessedModel.getInitialStates().getNextSetIndex(0)] << " (value in initial state)."); STORM_LOG_DEBUG("Unbounded weighted phase result: " << weightedResult[data.preprocessedModel.getInitialStates().getNextSetIndex(0)] << " (value in initial state).");
unboundedIndividualPhase(weightVector); unboundedIndividualPhase(weightVector);
STORM_LOG_DEBUG("Unbounded individual phase results in initial state: " << getInitialStateResultOfObjectives<double>());
if(!this->unboundedObjectives.full()) { if(!this->unboundedObjectives.full()) {
boundedPhase(weightVector, weightedRewardVector); boundedPhase(weightVector, weightedRewardVector);
STORM_LOG_DEBUG("Bounded individual phase results in initial state: " << getInitialStateResultOfObjectives<double>() << " ...WeightVectorChecker done.");
} }
STORM_LOG_DEBUG("Weight vector check done. Lower bounds for results in initial state: " << storm::utility::vector::convertNumericVector<double>(getLowerBoundsOfInitialStateResults()));
} }
template <class SparseModelType> template <class SparseModelType>
template<typename TargetValueType>
std::vector<TargetValueType> SparseMultiObjectiveWeightVectorChecker<SparseModelType>::getInitialStateResultOfObjectives() const {
void SparseMultiObjectiveWeightVectorChecker<SparseModelType>::setMaximumLowerUpperBoundGap(ValueType const& value) {
this->maximumLowerUpperBoundGap = value;
}
template <class SparseModelType>
typename SparseMultiObjectiveWeightVectorChecker<SparseModelType>::ValueType const& SparseMultiObjectiveWeightVectorChecker<SparseModelType>::getMaximumLowerUpperBoundGap() const {
return this->maximumLowerUpperBoundGap;
}
template <class SparseModelType>
std::vector<typename SparseMultiObjectiveWeightVectorChecker<SparseModelType>::ValueType> SparseMultiObjectiveWeightVectorChecker<SparseModelType>::getLowerBoundsOfInitialStateResults() const {
STORM_LOG_THROW(checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException, "Tried to retrieve results but check(..) has not been called before."); STORM_LOG_THROW(checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException, "Tried to retrieve results but check(..) has not been called before.");
STORM_LOG_ASSERT(data.preprocessedModel.getInitialStates().getNumberOfSetBits()==1, "The considered model has multiple initial states");
std::vector<TargetValueType> res;
res.reserve(objectiveResults.size());
for(auto const& objResult : objectiveResults) {
res.push_back(storm::utility::convertNumber<TargetValueType>(objResult[*data.preprocessedModel.getInitialStates().begin()]));
uint_fast64_t initstate = *this->data.preprocessedModel.getInitialStates().begin();
std::vector<ValueType> res;
res.reserve(this->data.objectives.size());
for(uint_fast64_t objIndex = 0; objIndex < this->data.objectives.size(); ++objIndex) {
res.push_back(this->objectiveResults[objIndex][initstate] + this->offsetsToLowerBound[objIndex]);
}
return res;
}
template <class SparseModelType>
std::vector<typename SparseMultiObjectiveWeightVectorChecker<SparseModelType>::ValueType> SparseMultiObjectiveWeightVectorChecker<SparseModelType>::getUpperBoundsOfInitialStateResults() const {
STORM_LOG_THROW(checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException, "Tried to retrieve results but check(..) has not been called before.");
uint_fast64_t initstate = *this->data.preprocessedModel.getInitialStates().begin();
std::vector<ValueType> res;
res.reserve(this->data.objectives.size());
for(uint_fast64_t objIndex = 0; objIndex < this->data.objectives.size(); ++objIndex) {
res.push_back(this->objectiveResults[objIndex][initstate] + this->offsetsToUpperBound[objIndex]);
} }
return res; return res;
} }
@ -147,6 +167,8 @@ namespace storm {
//one check can be omitted as the result can be computed back from the weighed result and the results from the remaining objectives //one check can be omitted as the result can be computed back from the weighed result and the results from the remaining objectives
for(uint_fast64_t objIndex = 0; objIndex < data.objectives.size(); ++objIndex) { for(uint_fast64_t objIndex = 0; objIndex < data.objectives.size(); ++objIndex) {
if(unboundedObjectives.get(objIndex)){ if(unboundedObjectives.get(objIndex)){
offsetsToLowerBound[objIndex] = storm::utility::zero<ValueType>();
offsetsToUpperBound[objIndex] = storm::utility::zero<ValueType>();
storm::utility::vector::selectVectorValues(deterministicStateRewards, this->scheduler.getChoices(), data.preprocessedModel.getTransitionMatrix().getRowGroupIndices(), discreteActionRewards[objIndex]); storm::utility::vector::selectVectorValues(deterministicStateRewards, this->scheduler.getChoices(), data.preprocessedModel.getTransitionMatrix().getRowGroupIndices(), discreteActionRewards[objIndex]);
storm::storage::BitVector statesWithRewards = ~storm::utility::vector::filterZero(deterministicStateRewards); storm::storage::BitVector statesWithRewards = ~storm::utility::vector::filterZero(deterministicStateRewards);
// As target states, we pick the states from which no reward is reachable. // As target states, we pick the states from which no reward is reachable.
@ -166,19 +188,10 @@ namespace storm {
} }
template class SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<double>>; template class SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<double>>;
template std::vector<double> SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<double>>::getInitialStateResultOfObjectives<double>() const;
template class SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>; template class SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>;
template std::vector<double> SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>::getInitialStateResultOfObjectives<double>() const;
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template std::vector<storm::RationalNumber> SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<double>>::getInitialStateResultOfObjectives<storm::RationalNumber>() const;
template std::vector<storm::RationalNumber> SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>::getInitialStateResultOfObjectives<storm::RationalNumber>() const;
template class SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<storm::RationalNumber>>; template class SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<storm::RationalNumber>>;
template std::vector<double> SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<storm::RationalNumber>>::getInitialStateResultOfObjectives<double>() const;
template class SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>; template class SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>;
template std::vector<double> SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::getInitialStateResultOfObjectives<double>() const;
template std::vector<storm::RationalNumber> SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<storm::RationalNumber>>::getInitialStateResultOfObjectives<storm::RationalNumber>() const;
template std::vector<storm::RationalNumber> SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::getInitialStateResultOfObjectives<storm::RationalNumber>() const;
#endif #endif
} }

38
src/modelchecker/multiobjective/helper/SparseMultiObjectiveWeightVectorChecker.h

@ -22,7 +22,7 @@ namespace storm {
typedef typename SparseModelType::ValueType ValueType; typedef typename SparseModelType::ValueType ValueType;
typedef typename SparseModelType::RewardModelType RewardModelType; typedef typename SparseModelType::RewardModelType RewardModelType;
typedef SparseMultiObjectivePreprocessorData<SparseModelType> PreprocessorData; typedef SparseMultiObjectivePreprocessorData<SparseModelType> PreprocessorData;
SparseMultiObjectiveWeightVectorChecker(PreprocessorData const& data); SparseMultiObjectiveWeightVectorChecker(PreprocessorData const& data);
/*! /*!
@ -33,13 +33,28 @@ namespace storm {
void check(std::vector<ValueType> const& weightVector); void check(std::vector<ValueType> const& weightVector);
/*! /*!
* Getter methods for the results of the most recent call of check(..)
* Sets the maximum gap that is allowed between the lower and upper bound of the result of some objective.
*/
void setMaximumLowerUpperBoundGap(ValueType const& value);
/*!
* Retrieves the maximum gap that is allowed between the lower and upper bound of the result of some objective.
*/
ValueType const& getMaximumLowerUpperBoundGap() const;
/*!
* Retrieves the results of the individual objectives at the initial state of the given model.
* Note that check(..) has to be called before retrieving results. Otherwise, an exception is thrown. * Note that check(..) has to be called before retrieving results. Otherwise, an exception is thrown.
* Also note that there is no guarantee that the lower/upper bounds are sound
* as long as the underlying solution methods are unsound (e.g., standard value iteration).
*/
std::vector<ValueType> getLowerBoundsOfInitialStateResults() const;
std::vector<ValueType> getUpperBoundsOfInitialStateResults() const;
/*!
* Retrieves a scheduler that induces the current values
* Note that check(..) has to be called before retrieving the scheduler. Otherwise, an exception is thrown.
*/ */
// The results of the individual objectives at the initial state of the given model
template<typename TargetValueType = ValueType>
std::vector<TargetValueType> getInitialStateResultOfObjectives() const;
// A scheduler that induces the optimal values
storm::storage::TotalScheduler const& getScheduler() const; storm::storage::TotalScheduler const& getScheduler() const;
@ -85,10 +100,19 @@ namespace storm {
// becomes true after the first call of check(..) // becomes true after the first call of check(..)
bool checkHasBeenCalled; bool checkHasBeenCalled;
// stores the maximum gap that is allowed between the lower and upper bound of the result of some objective.
ValueType maximumLowerUpperBoundGap;
// The result for the weighted reward vector (for all states of the model) // The result for the weighted reward vector (for all states of the model)
std::vector<ValueType> weightedResult; std::vector<ValueType> weightedResult;
// The results for the individual objectives (for all states of the model)
// The lower bounds of the results for the individual objectives (w.r.t. all states of the model)
std::vector<std::vector<ValueType>> objectiveResults; std::vector<std::vector<ValueType>> objectiveResults;
// Stores for each objective the distance between the computed result (w.r.t. the initial state) and a lower/upper bound for the actual result.
// The distances are stored as a (possibly negative) offset that has to be added to to the objectiveResults.
// Note that there is no guarantee that the lower/upper bounds are sound as long as the underlying solution method is not sound (e.g. standard value iteration).
std::vector<ValueType> offsetsToLowerBound;
std::vector<ValueType> offsetsToUpperBound;
// The scheduler that maximizes the weighted rewards // The scheduler that maximizes the weighted rewards
storm::storage::TotalScheduler scheduler; storm::storage::TotalScheduler scheduler;

2
src/modelchecker/results/ParetoCurveCheckResult.cpp

@ -65,7 +65,7 @@ namespace storm {
out << std::endl; out << std::endl;
out << "Underapproximation of achievable values: " << underApproximation->toString() << std::endl; out << "Underapproximation of achievable values: " << underApproximation->toString() << std::endl;
out << "Overapproximation of achievable values: " << overApproximation->toString() << std::endl; out << "Overapproximation of achievable values: " << overApproximation->toString() << std::endl;
out << points.size() << " pareto optimal points found:" << std::endl;
out << points.size() << " pareto optimal points found (Note that these points are safe, i.e., contained in the underapproximation, but there is no guarantee for optimality):" << std::endl;
for(auto const& p : points) { for(auto const& p : points) {
out << " ("; out << " (";
for(auto it = p.begin(); it != p.end(); ++it){ for(auto it = p.begin(); it != p.end(); ++it){

Loading…
Cancel
Save