Browse Source

split weight vector checker into one for MDPs and one for MAs

Former-commit-id: 142a151f3c
tempestpy_adaptions
TimQu 9 years ago
parent
commit
0e34bdbfc4
  1. 4
      src/modelchecker/multiobjective/SparseMaMultiObjectiveModelChecker.cpp
  2. 4
      src/modelchecker/multiobjective/SparseMdpMultiObjectiveModelChecker.cpp
  3. 88
      src/modelchecker/multiobjective/helper/SparseMaMultiObjectiveWeightVectorChecker.cpp
  4. 47
      src/modelchecker/multiobjective/helper/SparseMaMultiObjectiveWeightVectorChecker.h
  5. 85
      src/modelchecker/multiobjective/helper/SparseMdpMultiObjectiveWeightVectorChecker.cpp
  6. 51
      src/modelchecker/multiobjective/helper/SparseMdpMultiObjectiveWeightVectorChecker.h
  7. 27
      src/modelchecker/multiobjective/helper/SparseMultiObjectiveHelper.cpp
  8. 11
      src/modelchecker/multiobjective/helper/SparseMultiObjectiveHelper.h
  9. 108
      src/modelchecker/multiobjective/helper/SparseMultiObjectiveWeightVectorChecker.cpp
  10. 16
      src/modelchecker/multiobjective/helper/SparseMultiObjectiveWeightVectorChecker.h

4
src/modelchecker/multiobjective/SparseMaMultiObjectiveModelChecker.cpp

@ -10,6 +10,7 @@
#include "src/modelchecker/results/ExplicitQuantitativeCheckResult.h"
#include "src/modelchecker/multiobjective/helper/SparseMultiObjectivePreprocessor.h"
#include "src/modelchecker/multiobjective/helper/SparseMaMultiObjectiveWeightVectorChecker.h"
#include "src/modelchecker/multiobjective/helper/SparseMultiObjectiveHelper.h"
#include "src/modelchecker/multiobjective/helper/SparseMultiObjectivePostprocessor.h"
@ -47,7 +48,8 @@ namespace storm {
STORM_LOG_DEBUG("Preprocessing done. Data: " << preprocessorData);
storm::utility::Stopwatch swHelper;
auto resultData = helper::SparseMultiObjectiveHelper<SparseMaModelType, storm::RationalNumber>::check(preprocessorData);
std::shared_ptr<helper::SparseMultiObjectiveWeightVectorChecker<SparseMaModelType>> weightVectorChecker( new helper::SparseMaMultiObjectiveWeightVectorChecker<SparseMaModelType>(preprocessorData));
auto resultData = helper::SparseMultiObjectiveHelper<SparseMaModelType, storm::RationalNumber>::check(preprocessorData, weightVectorChecker);
swHelper.pause();
STORM_LOG_DEBUG("Modelchecking done.");

4
src/modelchecker/multiobjective/SparseMdpMultiObjectiveModelChecker.cpp

@ -10,6 +10,7 @@
#include "src/modelchecker/results/ExplicitQuantitativeCheckResult.h"
#include "src/modelchecker/multiobjective/helper/SparseMultiObjectivePreprocessor.h"
#include "src/modelchecker/multiobjective/helper/SparseMdpMultiObjectiveWeightVectorChecker.h"
#include "src/modelchecker/multiobjective/helper/SparseMultiObjectiveHelper.h"
#include "src/modelchecker/multiobjective/helper/SparseMultiObjectivePostprocessor.h"
@ -46,7 +47,8 @@ namespace storm {
STORM_LOG_DEBUG("Preprocessing done. Data: " << preprocessorData);
storm::utility::Stopwatch swHelper;
auto resultData = helper::SparseMultiObjectiveHelper<SparseMdpModelType, storm::RationalNumber>::check(preprocessorData);
std::shared_ptr<helper::SparseMultiObjectiveWeightVectorChecker<SparseMdpModelType>> weightVectorChecker( new helper::SparseMdpMultiObjectiveWeightVectorChecker<SparseMdpModelType>(preprocessorData));
auto resultData = helper::SparseMultiObjectiveHelper<SparseMdpModelType, storm::RationalNumber>::check(preprocessorData, weightVectorChecker);
swHelper.pause();
STORM_LOG_DEBUG("Modelchecking done.");

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

@ -0,0 +1,88 @@
#include "src/modelchecker/multiobjective/helper/SparseMaMultiObjectiveWeightVectorChecker.h"
#include "src/adapters/CarlAdapter.h"
#include "src/models/sparse/MarkovAutomaton.h"
#include "src/models/sparse/StandardRewardModel.h"
#include "src/utility/macros.h"
#include "src/utility/vector.h"
namespace storm {
namespace modelchecker {
namespace helper {
template <class SparseMaModelType>
SparseMaMultiObjectiveWeightVectorChecker<SparseMaModelType>::SparseMaMultiObjectiveWeightVectorChecker(PreprocessorData const& data) : SparseMultiObjectiveWeightVectorChecker<SparseMaModelType>(data) {
// Intentionally left empty
}
template <class SparseMaModelType>
std::vector<typename SparseMaMultiObjectiveWeightVectorChecker<SparseMaModelType>::ValueType> SparseMaMultiObjectiveWeightVectorChecker<SparseMaModelType>::getObjectiveRewardAsDiscreteActionRewards(uint_fast64_t objectiveIndex) const {
// Assert that the state and transition rewards have already been removed in prerpocessing
STORM_LOG_ASSERT(!this->data.preprocessedModel.getRewardModel(this->data.objectives[objectiveIndex].rewardModelName).hasStateRewards(), "Reward model has state rewards which is not expected.");
STORM_LOG_ASSERT(!this->data.preprocessedModel.getRewardModel(this->data.objectives[objectiveIndex].rewardModelName).hasTransitionRewards(), "Reward model has transition rewards which is not expected.");
return this->data.preprocessedModel.getRewardModel(this->data.objectives[objectiveIndex].rewardModelName).getStateActionRewardVector();
}
template <class SparseMaModelType>
void SparseMaMultiObjectiveWeightVectorChecker<SparseMaModelType>::boundedPhase(std::vector<ValueType> const& weightVector, std::vector<ValueType>& weightedRewardVector) {
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
std::vector<uint_fast64_t> optimalChoicesInCurrentEpoch(this->data.preprocessedModel.getNumberOfStates());
std::vector<ValueType> choiceValues(weightedRewardVector.size());
std::vector<ValueType> temporaryResult(this->data.preprocessedModel.getNumberOfStates());
// Get for each occurring timeBound the indices of the objectives with that bound.
std::map<uint_fast64_t, storm::storage::BitVector, std::greater<uint_fast64_t>> timeBounds;
storm::storage::BitVector boundedObjectives = ~this->unboundedObjectives;
for(uint_fast64_t objIndex : boundedObjectives) {
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;
timeBoundIt->second.set(objIndex);
}
storm::storage::BitVector objectivesAtCurrentEpoch = this->unboundedObjectives;
auto timeBoundIt = timeBounds.begin();
for(uint_fast64_t currentEpoch = timeBoundIt->first; currentEpoch > 0; --currentEpoch) {
if(timeBoundIt != timeBounds.end() && currentEpoch == timeBoundIt->first) {
objectivesAtCurrentEpoch |= timeBoundIt->second;
for(auto objIndex : timeBoundIt->second) {
storm::utility::vector::addScaledVector(weightedRewardVector, getObjectiveRewardAsDiscreteActionRewards(objIndex), weightVector[objIndex]);
}
++timeBoundIt;
}
// Get values and scheduler for weighted sum of objectives
this->data.preprocessedModel.getTransitionMatrix().multiplyWithVector(this->weightedResult, choiceValues);
storm::utility::vector::addVectors(choiceValues, weightedRewardVector, choiceValues);
storm::utility::vector::reduceVectorMax(choiceValues, this->weightedResult, this->data.preprocessedModel.getTransitionMatrix().getRowGroupIndices(), &optimalChoicesInCurrentEpoch);
// get values for individual objectives
// 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) {
std::vector<ValueType>& objectiveResult = this->objectiveResults[objIndex];
std::vector<ValueType> objectiveRewards = getObjectiveRewardAsDiscreteActionRewards(objIndex);
auto rowGroupIndexIt = this->data.preprocessedModel.getTransitionMatrix().getRowGroupIndices().begin();
auto optimalChoiceIt = optimalChoicesInCurrentEpoch.begin();
for(ValueType& stateValue : temporaryResult){
uint_fast64_t row = (*rowGroupIndexIt) + (*optimalChoiceIt);
++rowGroupIndexIt;
++optimalChoiceIt;
stateValue = objectiveRewards[row];
for(auto const& entry : this->data.preprocessedModel.getTransitionMatrix().getRow(row)) {
stateValue += entry.getValue() * objectiveResult[entry.getColumn()];
}
}
objectiveResult.swap(temporaryResult);
}
}
*/
}
template class SparseMaMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>;
#ifdef STORM_HAVE_CARL
template class SparseMaMultiObjectiveWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>;
#endif
}
}
}

47
src/modelchecker/multiobjective/helper/SparseMaMultiObjectiveWeightVectorChecker.h

@ -0,0 +1,47 @@
#ifndef STORM_MODELCHECKER_MULTIOBJECTIVE_HELPER_SPARSEMAMULTIOBJECTIVEWEIGHTVECTORCHECKER_H_
#define STORM_MODELCHECKER_MULTIOBJECTIVE_HELPER_SPARSEMAMULTIOBJECTIVEWEIGHTVECTORCHECKER_H_
#include <vector>
#include "src/modelchecker/multiobjective/helper/SparseMultiObjectiveWeightVectorChecker.h"
namespace storm {
namespace modelchecker {
namespace helper {
/*!
* Helper Class that takes preprocessed multi objective data and a weight vector and ...
* - computes the maximal expected reward w.r.t. the weighted sum of the rewards of the individual objectives
* - extracts the scheduler that induces this maximum
* - computes for each objective the value induced by this scheduler
*/
template <class SparseMaModelType>
class SparseMaMultiObjectiveWeightVectorChecker : public SparseMultiObjectiveWeightVectorChecker<SparseMaModelType> {
public:
typedef typename SparseMaModelType::ValueType ValueType;
typedef SparseMultiObjectivePreprocessorData<SparseMaModelType> PreprocessorData;
SparseMaMultiObjectiveWeightVectorChecker(PreprocessorData const& data);
private:
/*!
* Retrieves the rewards for the objective with the given index as state action reward vector.
*/
virtual std::vector<ValueType> getObjectiveRewardAsDiscreteActionRewards(uint_fast64_t objectiveIndex) const override;
/*!
*
* @param weightVector the weight vector of the current check
* @param weightedRewardVector the weighted rewards (initially only considering the unbounded objectives, will be extended to all objectives)
*/
virtual void boundedPhase(std::vector<ValueType> const& weightVector, std::vector<ValueType>& weightedRewardVector) override;
};
}
}
}
#endif /* STORM_MODELCHECKER_MULTIOBJECTIVE_HELPER_SPARSEMAMULTIOBJECTIVEWEIGHTEDVECTORCHECKER_H_ */

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

@ -0,0 +1,85 @@
#include "src/modelchecker/multiobjective/helper/SparseMdpMultiObjectiveWeightVectorChecker.h"
#include "src/adapters/CarlAdapter.h"
#include "src/models/sparse/Mdp.h"
#include "src/models/sparse/StandardRewardModel.h"
#include "src/utility/macros.h"
#include "src/utility/vector.h"
namespace storm {
namespace modelchecker {
namespace helper {
template <class SparseMdpModelType>
SparseMdpMultiObjectiveWeightVectorChecker<SparseMdpModelType>::SparseMdpMultiObjectiveWeightVectorChecker(PreprocessorData const& data) : SparseMultiObjectiveWeightVectorChecker<SparseMdpModelType>(data) {
// Intentionally left empty
}
template <class SparseMdpModelType>
std::vector<typename SparseMdpMultiObjectiveWeightVectorChecker<SparseMdpModelType>::ValueType> SparseMdpMultiObjectiveWeightVectorChecker<SparseMdpModelType>::getObjectiveRewardAsDiscreteActionRewards(uint_fast64_t objectiveIndex) const {
// Assert that the state and transition rewards have already been removed in prerpocessing
STORM_LOG_ASSERT(!this->data.preprocessedModel.getRewardModel(this->data.objectives[objectiveIndex].rewardModelName).hasStateRewards(), "Reward model has state rewards which is not expected.");
STORM_LOG_ASSERT(!this->data.preprocessedModel.getRewardModel(this->data.objectives[objectiveIndex].rewardModelName).hasTransitionRewards(), "Reward model has transition rewards which is not expected.");
return this->data.preprocessedModel.getRewardModel(this->data.objectives[objectiveIndex].rewardModelName).getStateActionRewardVector();
}
template <class SparseMdpModelType>
void SparseMdpMultiObjectiveWeightVectorChecker<SparseMdpModelType>::boundedPhase(std::vector<ValueType> const& weightVector, std::vector<ValueType>& weightedRewardVector) {
// 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<ValueType> choiceValues(weightedRewardVector.size());
std::vector<ValueType> temporaryResult(this->data.preprocessedModel.getNumberOfStates());
// Get for each occurring timeBound the indices of the objectives with that bound.
std::map<uint_fast64_t, storm::storage::BitVector, std::greater<uint_fast64_t>> timeBounds;
storm::storage::BitVector boundedObjectives = ~this->unboundedObjectives;
for(uint_fast64_t objIndex : boundedObjectives) {
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;
timeBoundIt->second.set(objIndex);
}
storm::storage::BitVector objectivesAtCurrentEpoch = this->unboundedObjectives;
auto timeBoundIt = timeBounds.begin();
for(uint_fast64_t currentEpoch = timeBoundIt->first; currentEpoch > 0; --currentEpoch) {
if(timeBoundIt != timeBounds.end() && currentEpoch == timeBoundIt->first) {
objectivesAtCurrentEpoch |= timeBoundIt->second;
for(auto objIndex : timeBoundIt->second) {
storm::utility::vector::addScaledVector(weightedRewardVector, getObjectiveRewardAsDiscreteActionRewards(objIndex), weightVector[objIndex]);
}
++timeBoundIt;
}
// Get values and scheduler for weighted sum of objectives
this->data.preprocessedModel.getTransitionMatrix().multiplyWithVector(this->weightedResult, choiceValues);
storm::utility::vector::addVectors(choiceValues, weightedRewardVector, choiceValues);
storm::utility::vector::reduceVectorMax(choiceValues, this->weightedResult, this->data.preprocessedModel.getTransitionMatrix().getRowGroupIndices(), &optimalChoicesInCurrentEpoch);
// get values for individual objectives
// 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) {
std::vector<ValueType>& objectiveResult = this->objectiveResults[objIndex];
std::vector<ValueType> objectiveRewards = getObjectiveRewardAsDiscreteActionRewards(objIndex);
auto rowGroupIndexIt = this->data.preprocessedModel.getTransitionMatrix().getRowGroupIndices().begin();
auto optimalChoiceIt = optimalChoicesInCurrentEpoch.begin();
for(ValueType& stateValue : temporaryResult){
uint_fast64_t row = (*rowGroupIndexIt) + (*optimalChoiceIt);
++rowGroupIndexIt;
++optimalChoiceIt;
stateValue = objectiveRewards[row];
for(auto const& entry : this->data.preprocessedModel.getTransitionMatrix().getRow(row)) {
stateValue += entry.getValue() * objectiveResult[entry.getColumn()];
}
}
objectiveResult.swap(temporaryResult);
}
}
}
template class SparseMdpMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<double>>;
#ifdef STORM_HAVE_CARL
template class SparseMdpMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<storm::RationalNumber>>;
#endif
}
}
}

51
src/modelchecker/multiobjective/helper/SparseMdpMultiObjectiveWeightVectorChecker.h

@ -0,0 +1,51 @@
#ifndef STORM_MODELCHECKER_MULTIOBJECTIVE_HELPER_SPARSEMDPMULTIOBJECTIVEWEIGHTVECTORCHECKER_H_
#define STORM_MODELCHECKER_MULTIOBJECTIVE_HELPER_SPARSEMDPMULTIOBJECTIVEWEIGHTVECTORCHECKER_H_
#include <vector>
#include "src/modelchecker/multiobjective/helper/SparseMultiObjectiveWeightVectorChecker.h"
namespace storm {
namespace modelchecker {
namespace helper {
/*!
* Helper Class that takes preprocessed multi objective data and a weight vector and ...
* - computes the maximal expected reward w.r.t. the weighted sum of the rewards of the individual objectives
* - extracts the scheduler that induces this maximum
* - computes for each objective the value induced by this scheduler
*/
template <class SparseMdpModelType>
class SparseMdpMultiObjectiveWeightVectorChecker : public SparseMultiObjectiveWeightVectorChecker<SparseMdpModelType> {
public:
typedef typename SparseMdpModelType::ValueType ValueType;
typedef SparseMultiObjectivePreprocessorData<SparseMdpModelType> PreprocessorData;
SparseMdpMultiObjectiveWeightVectorChecker(PreprocessorData const& data);
private:
/*!
* Retrieves the rewards for the objective with the given index as state action reward vector.
*/
virtual std::vector<ValueType> getObjectiveRewardAsDiscreteActionRewards(uint_fast64_t objectiveIndex) const override;
/*!
* For each time epoch (starting with the maximal stepBound occurring in the objectives), this method
* - determines the objectives that are relevant in the current time epoch
* - determines the maximizing scheduler for the weighted reward vector of these objectives
* - computes the values of these objectives w.r.t. this scheduler
*
* @param weightVector the weight vector of the current check
* @param weightedRewardVector the weighted rewards (initially only considering the unbounded objectives, will be extended to all objectives)
*/
virtual void boundedPhase(std::vector<ValueType> const& weightVector, std::vector<ValueType>& weightedRewardVector) override;
};
}
}
}
#endif /* STORM_MODELCHECKER_MULTIOBJECTIVE_HELPER_SPARSEMDPMULTIOBJECTIVEWEIGHTEDVECTORCHECKER_H_ */

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

@ -18,7 +18,7 @@ namespace storm {
template <class SparseModelType, typename RationalNumberType>
typename SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::ResultData SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::check(PreprocessorData const& preprocessorData) {
typename SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::ResultData SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::check(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker) {
ResultData resultData;
resultData.overApproximation() = storm::storage::geometry::Polytope<RationalNumberType>::createUniversalPolytope();
resultData.underApproximation() = storm::storage::geometry::Polytope<RationalNumberType>::createEmptyPolytope();
@ -26,13 +26,13 @@ namespace storm {
if(!checkIfPreprocessingWasConclusive(preprocessorData)) {
switch(preprocessorData.queryType) {
case PreprocessorData::QueryType::Achievability:
achievabilityQuery(preprocessorData, resultData);
achievabilityQuery(preprocessorData, weightVectorChecker, resultData);
break;
case PreprocessorData::QueryType::Numerical:
numericalQuery(preprocessorData, resultData);
numericalQuery(preprocessorData, weightVectorChecker, resultData);
break;
case PreprocessorData::QueryType::Pareto:
paretoQuery(preprocessorData, resultData);
paretoQuery(preprocessorData, weightVectorChecker, resultData);
break;
default:
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unknown Query Type");
@ -56,7 +56,7 @@ namespace storm {
}
template <class SparseModelType, typename RationalNumberType>
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::achievabilityQuery(PreprocessorData const& preprocessorData, ResultData& resultData) {
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::achievabilityQuery(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker, ResultData& resultData) {
Point thresholds;
thresholds.reserve(preprocessorData.objectives.size());
storm::storage::BitVector strictThresholds(preprocessorData.objectives.size());
@ -66,7 +66,6 @@ namespace storm {
}
storm::storage::BitVector individualObjectivesToBeChecked(preprocessorData.objectives.size(), true);
SparseMultiObjectiveWeightVectorChecker<SparseModelType> weightVectorChecker(preprocessorData);
do {
WeightVector separatingVector = findSeparatingVector(thresholds, resultData.underApproximation(), individualObjectivesToBeChecked);
performRefinementStep(separatingVector, preprocessorData.produceSchedulers, weightVectorChecker, resultData);
@ -80,7 +79,7 @@ namespace storm {
}
template <class SparseModelType, typename RationalNumberType>
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::numericalQuery(PreprocessorData const& preprocessorData, 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.");
uint_fast64_t optimizingObjIndex = *preprocessorData.indexOfOptimizingObjective;
Point thresholds;
@ -107,7 +106,6 @@ namespace storm {
// Try to find one valid solution
storm::storage::BitVector individualObjectivesToBeChecked(preprocessorData.objectives.size(), true);
individualObjectivesToBeChecked.set(optimizingObjIndex, false);
SparseMultiObjectiveWeightVectorChecker<SparseModelType> weightVectorChecker(preprocessorData);
do {
WeightVector separatingVector = findSeparatingVector(thresholds, resultData.underApproximation(), individualObjectivesToBeChecked);
performRefinementStep(separatingVector, preprocessorData.produceSchedulers, weightVectorChecker, resultData);
@ -150,8 +148,7 @@ namespace storm {
}
template <class SparseModelType, typename RationalNumberType>
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::paretoQuery(PreprocessorData const& preprocessorData, ResultData& resultData) {
SparseMultiObjectiveWeightVectorChecker<SparseModelType> weightVectorChecker(preprocessorData);
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::paretoQuery(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker, ResultData& resultData) {
//First consider the objectives individually
for(uint_fast64_t objIndex = 0; objIndex<preprocessorData.objectives.size() && !maxStepsPerformed(resultData); ++objIndex) {
WeightVector direction(preprocessorData.objectives.size(), storm::utility::zero<RationalNumberType>());
@ -228,13 +225,13 @@ namespace storm {
}
template <class SparseModelType, typename RationalNumberType>
void SparseMultiObjectiveHelper<SparseModelType, RationalNumberType>::performRefinementStep(WeightVector const& direction, bool saveScheduler, SparseMultiObjectiveWeightVectorChecker<SparseModelType>& 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 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()));
if(saveScheduler) {
result.refinementSteps().emplace_back(direction, weightVectorChecker.template getInitialStateResultOfObjectives<RationalNumberType>(), weightVectorChecker.getScheduler());
result.refinementSteps().emplace_back(direction, weightVectorChecker->template getInitialStateResultOfObjectives<RationalNumberType>(), weightVectorChecker->getScheduler());
} else {
result.refinementSteps().emplace_back(direction, weightVectorChecker.template getInitialStateResultOfObjectives<RationalNumberType>());
result.refinementSteps().emplace_back(direction, weightVectorChecker->template getInitialStateResultOfObjectives<RationalNumberType>());
}
updateOverApproximation(result.refinementSteps(), result.overApproximation());
updateUnderApproximation(result.refinementSteps(), result.underApproximation());

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

@ -19,11 +19,12 @@ namespace storm {
typedef SparseMultiObjectivePreprocessorData<SparseModelType> PreprocessorData;
typedef SparseMultiObjectiveResultData<RationalNumberType> ResultData;
typedef SparseMultiObjectiveRefinementStep<RationalNumberType> RefinementStep;
typedef std::shared_ptr<SparseMultiObjectiveWeightVectorChecker<SparseModelType>> WeightVectorCheckerType;
typedef std::vector<RationalNumberType> Point;
typedef std::vector<RationalNumberType> WeightVector;
static ResultData check(PreprocessorData const& preprocessorData);
static ResultData check(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker);
private:
@ -34,9 +35,9 @@ namespace storm {
*/
static bool checkIfPreprocessingWasConclusive(PreprocessorData const& preprocessorData);
static void achievabilityQuery(PreprocessorData const& preprocessorData, ResultData& resultData);
static void numericalQuery(PreprocessorData const& preprocessorData, ResultData& resultData);
static void paretoQuery(PreprocessorData const& preprocessorData, ResultData& resultData);
static void achievabilityQuery(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker, ResultData& resultData);
static void numericalQuery(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker, ResultData& resultData);
static void paretoQuery(PreprocessorData const& preprocessorData, WeightVectorCheckerType weightVectorChecker, ResultData& resultData);
/*
* Returns a weight vector w that separates the under approximation from the given point p, i.e.,
@ -51,7 +52,7 @@ namespace storm {
/*
* Refines the current result w.r.t. the given direction vector
*/
static void performRefinementStep(WeightVector const& direction, bool saveScheduler, SparseMultiObjectiveWeightVectorChecker<SparseModelType>& weightVectorChecker, ResultData& resultData);
static void performRefinementStep(WeightVector const& direction, bool saveScheduler, WeightVectorCheckerType weightVectorChecker, ResultData& resultData);
/*
* Updates the overapproximation after a refinement step has been performed

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

@ -22,30 +22,33 @@ namespace storm {
template <class SparseModelType>
SparseMultiObjectiveWeightVectorChecker<SparseModelType>::SparseMultiObjectiveWeightVectorChecker(PreprocessorData const& data) : data(data), checkHasBeenCalled(false) , objectiveResults(data.objectives.size()){
SparseMultiObjectiveWeightVectorChecker<SparseModelType>::SparseMultiObjectiveWeightVectorChecker(PreprocessorData const& data) : data(data), unboundedObjectives(data.objectives.size()),checkHasBeenCalled(false), objectiveResults(data.objectives.size()){
// set the unbounded objectives
for(uint_fast64_t objIndex = 0; objIndex < data.objectives.size(); ++objIndex) {
unboundedObjectives.set(objIndex, !data.objectives[objIndex].timeBounds);
}
// Enlarge the set of prob1 states to the states that are only reachable via prob1 states
statesThatAreAllowedToBeVisitedInfinitelyOften = ~storm::utility::graph::getReachableStates(data.preprocessedModel.getTransitionMatrix(), data.preprocessedModel.getInitialStates(), ~data.preprocessedModel.getStates(data.prob1StatesLabel), storm::storage::BitVector(data.preprocessedModel.getNumberOfStates(), false));
}
template <class SparseModelType>
void SparseMultiObjectiveWeightVectorChecker<SparseModelType>::check(std::vector<ValueType> const& weightVector) {
checkHasBeenCalled=true;
STORM_LOG_DEBUG("Invoked WeightVectorChecker with weights " << std::endl << "\t" << storm::utility::vector::convertNumericVector<double>(weightVector));
storm::storage::BitVector unboundedObjectives(data.objectives.size(), false);
std::vector<ValueType> weightedRewardVector(data.preprocessedModel.getTransitionMatrix().getRowCount(), storm::utility::zero<ValueType>());
for(uint_fast64_t objIndex = 0; objIndex < data.objectives.size(); ++objIndex) {
if(!data.objectives[objIndex].timeBounds) {
unboundedObjectives.set(objIndex, true);
storm::utility::vector::addScaledVector(weightedRewardVector, data.preprocessedModel.getRewardModel(data.objectives[objIndex].rewardModelName).getStateActionRewardVector(), weightVector[objIndex]);
}
for(auto objIndex : unboundedObjectives) {
storm::utility::vector::addScaledVector(weightedRewardVector, getObjectiveRewardAsDiscreteActionRewards(objIndex), weightVector[objIndex]);
}
unboundedWeightedPhase(unboundedObjectives, weightedRewardVector);
unboundedWeightedPhase(weightedRewardVector);
STORM_LOG_DEBUG("Unbounded weighted phase result: " << weightedResult[data.preprocessedModel.getInitialStates().getNextSetIndex(0)] << " (value in initial state).");
unboundedIndividualPhase(weightVector);
STORM_LOG_DEBUG("Unbounded individual phase results in initial state: " << getInitialStateResultOfObjectives<double>());
boundedPhase(weightVector, ~unboundedObjectives, weightedRewardVector);
STORM_LOG_DEBUG("Bounded individual phase results in initial state: " << getInitialStateResultOfObjectives<double>() << " ...WeightVectorChecker done.");
if(!this->unboundedObjectives.full()) {
boundedPhase(weightVector, weightedRewardVector);
STORM_LOG_DEBUG("Bounded individual phase results in initial state: " << getInitialStateResultOfObjectives<double>() << " ...WeightVectorChecker done.");
}
}
template <class SparseModelType>
@ -63,16 +66,14 @@ namespace storm {
template <class SparseModelType>
storm::storage::TotalScheduler const& SparseMultiObjectiveWeightVectorChecker<SparseModelType>::getScheduler() const {
STORM_LOG_THROW(checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException, "Tried to retrieve results but check(..) has not been called before.");
for(auto const& obj : data.objectives) {
STORM_LOG_THROW(!obj.timeBounds, storm::exceptions::NotImplementedException, "Scheduler retrival is not implemented for timeBounded objectives.");
}
STORM_LOG_THROW(this->checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException, "Tried to retrieve results but check(..) has not been called before.");
STORM_LOG_THROW(this->unboundedObjectives.full(), storm::exceptions::NotImplementedException, "Scheduler retrival is not implemented for timeBounded objectives.");
return scheduler;
}
template <class SparseModelType>
void SparseMultiObjectiveWeightVectorChecker<SparseModelType>::unboundedWeightedPhase(storm::storage::BitVector const& unboundedObjectives, std::vector<ValueType> const& weightedRewardVector) {
if(unboundedObjectives.empty()) {
void SparseMultiObjectiveWeightVectorChecker<SparseModelType>::unboundedWeightedPhase(std::vector<ValueType> const& weightedRewardVector) {
if(this->unboundedObjectives.empty()) {
this->weightedResult = std::vector<ValueType>(data.preprocessedModel.getNumberOfStates(), storm::utility::zero<ValueType>());
this->scheduler = storm::storage::TotalScheduler(data.preprocessedModel.getNumberOfStates());
return;
@ -145,79 +146,24 @@ namespace storm {
//Also only compute values for objectives with weightVector != zero,
//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) {
if(data.objectives[objIndex].timeBounds){
objectiveResults[objIndex] = std::vector<ValueType>(data.preprocessedModel.getNumberOfStates(), storm::utility::zero<ValueType>());
} else {
storm::utility::vector::selectVectorValues(deterministicStateRewards, this->scheduler.getChoices(), data.preprocessedModel.getTransitionMatrix().getRowGroupIndices(), data.preprocessedModel.getRewardModel(data.objectives[objIndex].rewardModelName).getStateActionRewardVector());
if(unboundedObjectives.get(objIndex)){
storm::utility::vector::selectVectorValues(deterministicStateRewards, this->scheduler.getChoices(), data.preprocessedModel.getTransitionMatrix().getRowGroupIndices(), getObjectiveRewardAsDiscreteActionRewards(objIndex));
storm::storage::BitVector statesWithRewards = ~storm::utility::vector::filterZero(deterministicStateRewards);
// As target states, we pick the states from which no reward is reachable.
storm::storage::BitVector targetStates = ~storm::utility::graph::performProbGreater0(deterministicBackwardTransitions, storm::storage::BitVector(deterministicMatrix.getRowCount(), true), statesWithRewards);
//TODO: we could give the solver some hint for the result (e.g., weightVector[ObjIndex] * weightedResult or (weightedResult - sum_i=0^objIndex-1 objectiveResult) * weightVector[objIndex]/ sum_i=objIndex^n weightVector[i] )
objectiveResults[objIndex] = storm::modelchecker::helper::SparseDtmcPrctlHelper<ValueType>::computeReachabilityRewards(deterministicMatrix,
deterministicBackwardTransitions,
deterministicStateRewards,
targetStates,
false, //no qualitative checking,
linearEquationSolverFactory);
}
}
}
template <class SparseModelType>
void SparseMultiObjectiveWeightVectorChecker<SparseModelType>::boundedPhase(std::vector<ValueType> const& weightVector, storm::storage::BitVector const& boundedObjectives, std::vector<ValueType>& weightedRewardVector) {
if(boundedObjectives.empty()) {
return;
}
// Allocate some memory so this does not need to happen for each time epoch
std::vector<uint_fast64_t> optimalChoicesInCurrentEpoch(data.preprocessedModel.getNumberOfStates());
std::vector<ValueType> choiceValues(weightedRewardVector.size());
std::vector<ValueType> temporaryResult(data.preprocessedModel.getNumberOfStates());
// Get for each occurring timeBound the indices of the objectives with that bound.
std::map<uint_fast64_t, storm::storage::BitVector, std::greater<uint_fast64_t>> timeBounds;
for(auto objIndex : boundedObjectives) {
uint_fast64_t timeBound = boost::get<uint_fast64_t>(data.objectives[objIndex].timeBounds.get());
auto timeBoundIt = timeBounds.insert(std::make_pair(timeBound, storm::storage::BitVector(data.objectives.size(), false))).first;
timeBoundIt->second.set(objIndex);
}
storm::storage::BitVector objectivesAtCurrentEpoch = ~boundedObjectives;
auto timeBoundIt = timeBounds.begin();
for(uint_fast64_t currentEpoch = timeBoundIt->first; currentEpoch > 0; --currentEpoch) {
if(timeBoundIt != timeBounds.end() && currentEpoch == timeBoundIt->first) {
objectivesAtCurrentEpoch |= timeBoundIt->second;
for(auto objIndex : timeBoundIt->second) {
storm::utility::vector::addScaledVector(weightedRewardVector, data.preprocessedModel.getRewardModel(data.objectives[objIndex].rewardModelName).getStateActionRewardVector(), weightVector[objIndex]);
}
++timeBoundIt;
}
// Get values and scheduler for weighted sum of objectives
data.preprocessedModel.getTransitionMatrix().multiplyWithVector(weightedResult, choiceValues);
storm::utility::vector::addVectors(choiceValues, weightedRewardVector, choiceValues);
storm::utility::vector::reduceVectorMax(choiceValues, weightedResult, data.preprocessedModel.getTransitionMatrix().getRowGroupIndices(), &optimalChoicesInCurrentEpoch);
// get values for individual objectives
// 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) {
std::vector<ValueType>& objectiveResult = objectiveResults[objIndex];
std::vector<ValueType> const& objectiveRewards = data.preprocessedModel.getRewardModel(data.objectives[objIndex].rewardModelName).getStateActionRewardVector();
auto rowGroupIndexIt = data.preprocessedModel.getTransitionMatrix().getRowGroupIndices().begin();
auto optimalChoiceIt = optimalChoicesInCurrentEpoch.begin();
for(ValueType& stateValue : temporaryResult){
uint_fast64_t row = (*rowGroupIndexIt) + (*optimalChoiceIt);
++rowGroupIndexIt;
++optimalChoiceIt;
stateValue = objectiveRewards[row];
for(auto const& entry : data.preprocessedModel.getTransitionMatrix().getRow(row)) {
stateValue += entry.getValue() * objectiveResult[entry.getColumn()];
}
}
objectiveResult.swap(temporaryResult);
deterministicBackwardTransitions,
deterministicStateRewards,
targetStates,
false, //no qualitative checking,
linearEquationSolverFactory);
} else {
objectiveResults[objIndex] = std::vector<ValueType>(data.preprocessedModel.getNumberOfStates(), storm::utility::zero<ValueType>());
}
}
}
template class SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<double>>;
template std::vector<double> SparseMultiObjectiveWeightVectorChecker<storm::models::sparse::Mdp<double>>::getInitialStateResultOfObjectives<double>() const;

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

@ -43,15 +43,20 @@ namespace storm {
storm::storage::TotalScheduler const& getScheduler() const;
private:
protected:
/*!
* Retrieves the rewards for the objective with the given index as state action reward vector.
* Note that this discretizes state rewards of Markovian states by dividing them with the exit rate.
*/
virtual std::vector<ValueType> getObjectiveRewardAsDiscreteActionRewards(uint_fast64_t objectiveIndex) const = 0 ;
/*!
* Determines the scheduler that maximizes the weighted reward vector of the unbounded objectives
*
* @param unboundedObjectives the objectives without a stepBound
* @param weightedRewardVector the weighted rewards (only considering the unbounded objectives)
*/
void unboundedWeightedPhase(storm::storage::BitVector const& unboundedObjectives, std::vector<ValueType> const& weightedRewardVector);
void unboundedWeightedPhase(std::vector<ValueType> const& weightedRewardVector);
/*!
* Computes the values of the objectives that do not have a stepBound w.r.t. the scheduler computed in the unboundedWeightedPhase
@ -67,13 +72,14 @@ namespace storm {
* - computes the values of these objectives w.r.t. this scheduler
*
* @param weightVector the weight vector of the current check
* @param boundedObjectives the objectives with a stepBound
* @param weightedRewardVector the weighted rewards (initially only considering the unbounded objectives, will be extended to all objectives)
*/
void boundedPhase(std::vector<ValueType> const& weightVector, storm::storage::BitVector const& unboundedObjectives, std::vector<ValueType>& weightedRewardVector);
virtual void boundedPhase(std::vector<ValueType> const& weightVector, std::vector<ValueType>& weightedRewardVector) = 0;
// stores the considered information of the multi-objective model checking problem
PreprocessorData const& data;
// stores the indices of the objectives for which there is no time bound
storm::storage::BitVector unboundedObjectives;
// stores the set of states for which it is allowed to visit them infinitely often
// This means that, if one of the states is part of a neutral EC, it is allowed to

Loading…
Cancel
Save