18namespace modelchecker {
19namespace multiobjective {
21template<
class SparseModelType,
typename GeometryValueType>
23 if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
24 STORM_PRINT_AND_LOG(
"Pareto Curve Approximation Algorithm terminated after " << this->refinementSteps.size() <<
" refinement steps.\n");
28template<
class SparseModelType,
typename GeometryValueType>
30 : originalModel(preprocessorResult.originalModel), originalFormula(preprocessorResult.originalFormula), objectives(preprocessorResult.objectives) {
38template<
class SparseModelType,
typename GeometryValueType>
40 Point const& pointToBeSeparated) {
41 STORM_LOG_DEBUG(
"Searching a weight vector to seperate the point given by "
44 if (underApproximation->isEmpty()) {
46 uint_fast64_t objIndex = diracWeightVectorsToBeChecked.getNextSetIndex(0) % pointToBeSeparated.size();
47 WeightVector result(pointToBeSeparated.size(), storm::utility::zero<GeometryValueType>());
48 result[objIndex] = storm::utility::one<GeometryValueType>();
49 diracWeightVectorsToBeChecked.set(objIndex,
false);
57 "Tried to find a separating point but the point is already contained in the underApproximation");
58 std::vector<storm::storage::geometry::Halfspace<GeometryValueType>> halfspaces = underApproximation->getHalfspaces();
59 uint_fast64_t farestHalfspaceIndex = halfspaces.size();
60 GeometryValueType farestDistance = -storm::utility::one<GeometryValueType>();
61 bool foundSeparatingDiracVector =
false;
62 for (uint_fast64_t halfspaceIndex = 0; halfspaceIndex < halfspaces.size(); ++halfspaceIndex) {
63 GeometryValueType distance = halfspaces[halfspaceIndex].euclideanDistance(pointToBeSeparated);
66 bool isSingleObjectiveVector =
69 if ((!foundSeparatingDiracVector && isSingleObjectiveVector) ||
70 (foundSeparatingDiracVector == isSingleObjectiveVector && distance > farestDistance)) {
71 foundSeparatingDiracVector = foundSeparatingDiracVector || isSingleObjectiveVector;
72 farestHalfspaceIndex = halfspaceIndex;
73 farestDistance = distance;
77 if (foundSeparatingDiracVector) {
78 diracWeightVectorsToBeChecked &= storm::utility::vector::filterZero<GeometryValueType>(halfspaces[farestHalfspaceIndex].normalVector());
81 STORM_LOG_THROW(farestHalfspaceIndex < halfspaces.size(), storm::exceptions::UnexpectedException,
"There is no seperating vector.");
85 return halfspaces[farestHalfspaceIndex].normalVector();
88template<
class SparseModelType,
typename GeometryValueType>
92 direction, storm::utility::one<GeometryValueType>() / std::accumulate(direction.begin(), direction.end(), storm::utility::zero<GeometryValueType>()));
93 weightVectorChecker->check(env, storm::utility::vector::convertNumericVector<typename SparseModelType::ValueType>(direction));
95 storm::utility::vector::convertNumericVector<double>(weightVectorChecker->getUnderApproximationOfInitialStateResults())));
98 step.
lowerBoundPoint = storm::utility::vector::convertNumericVector<GeometryValueType>(weightVectorChecker->getUnderApproximationOfInitialStateResults());
99 step.
upperBoundPoint = storm::utility::vector::convertNumericVector<GeometryValueType>(weightVectorChecker->getOverApproximationOfInitialStateResults());
101 for (uint_fast64_t objIndex = 0; objIndex < this->objectives.size(); ++objIndex) {
103 step.
lowerBoundPoint[objIndex] *= -storm::utility::one<GeometryValueType>();
104 step.
upperBoundPoint[objIndex] *= -storm::utility::one<GeometryValueType>();
107 if (produceScheduler) {
108 step.
scheduler = weightVectorChecker->computeScheduler();
110 refinementSteps.push_back(std::move(step));
112 updateOverApproximation();
113 updateUnderApproximation();
116template<
class SparseModelType,
typename GeometryValueType>
123 GeometryValueType maximumOffset = h.
offset();
124 for (
auto const& step : refinementSteps) {
127 if (maximumOffset > h.
offset()) {
129 h.
offset() = maximumOffset;
130 STORM_LOG_WARN(
"Numerical issues: The overapproximation would not contain the underapproximation. Hence, a halfspace is shifted by "
131 << storm::utility::convertNumber<double>(h.
invert().euclideanDistance(refinementSteps.back().upperBoundPoint)) <<
".");
133 overApproximation = overApproximation->intersection(h);
134 STORM_LOG_DEBUG(
"Updated OverApproximation to " << overApproximation->toString(
true));
137template<
class SparseModelType,
typename GeometryValueType>
139 std::vector<Point> paretoPoints;
140 paretoPoints.reserve(refinementSteps.size());
141 for (
auto const& step : refinementSteps) {
142 paretoPoints.push_back(step.lowerBoundPoint);
145 STORM_LOG_DEBUG(
"Updated UnderApproximation to " << underApproximation->toString(
true));
148template<
class SparseModelType,
typename GeometryValueType>
153template<
typename SparseModelType,
typename GeometryValueType>
155 STORM_LOG_ERROR_COND(objectives.size() == 2,
"Exporting plot requested but this is only implemented for the two-dimensional case.");
162 std::vector<GeometryValueType>(objectives.size(), storm::utility::zero<GeometryValueType>()),
163 std::vector<GeometryValueType>(objectives.size(), storm::utility::zero<GeometryValueType>()));
164 std::vector<std::vector<GeometryValueType>> paretoPoints;
165 paretoPoints.reserve(refinementSteps.size());
166 for (
auto const& step : refinementSteps) {
168 boundaries.
enlarge(paretoPoints.back());
170 auto underApproxVertices = transformedUnderApprox->getVertices();
171 for (
auto const& v : underApproxVertices) {
174 auto overApproxVertices = transformedOverApprox->getVertices();
175 for (
auto const& v : overApproxVertices) {
183 auto boundariesAsPolytope = boundaries.
asPolytope();
184 std::vector<std::string> columnHeaders = {
"x",
"y"};
186 std::vector<std::vector<double>> pointsForPlotting;
188 underApproxVertices = transformedUnderApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder();
189 pointsForPlotting.reserve(underApproxVertices.size());
190 for (
auto const& v : underApproxVertices) {
191 pointsForPlotting.push_back(storm::utility::vector::convertNumericVector<double>(v));
197 pointsForPlotting.clear();
198 overApproxVertices = transformedOverApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder();
199 pointsForPlotting.reserve(overApproxVertices.size());
200 for (
auto const& v : overApproxVertices) {
201 pointsForPlotting.push_back(storm::utility::vector::convertNumericVector<double>(v));
207 pointsForPlotting.clear();
208 pointsForPlotting.reserve(paretoPoints.size());
209 for (
auto const& v : paretoPoints) {
210 pointsForPlotting.push_back(storm::utility::vector::convertNumericVector<double>(v));
ModelCheckerEnvironment & modelchecker()
MultiObjectiveModelCheckerEnvironment & multi()
uint64_t const & getMaxSteps() const
boost::optional< std::string > getPlotPathOverApproximation() const
bool isMaxStepsSet() const
boost::optional< std::string > getPlotPathParetoPoints() const
boost::optional< std::string > getPlotPathUnderApproximation() const
SparsePcaaQuery(preprocessing::SparseMultiObjectivePreprocessorResult< SparseModelType > &preprocessorResult)
void updateUnderApproximation()
std::shared_ptr< storm::storage::geometry::Polytope< GeometryValueType > > overApproximation
WeightVector findSeparatingVector(Point const &pointToBeSeparated)
std::unique_ptr< PcaaWeightVectorChecker< SparseModelType > > weightVectorChecker
bool maxStepsPerformed(Environment const &env) const
virtual ~SparsePcaaQuery()
storm::storage::BitVector diracWeightVectorsToBeChecked
std::vector< GeometryValueType > WeightVector
void performRefinementStep(Environment const &env, WeightVector &&direction, bool produceScheduler)
std::shared_ptr< storm::storage::geometry::Polytope< GeometryValueType > > underApproximation
void updateOverApproximation()
void exportPlotOfCurrentApproximation(Environment const &env) const
std::vector< Objective< typename SparseModelType::ValueType > > objectives
std::vector< GeometryValueType > Point
static std::unique_ptr< PcaaWeightVectorChecker< ModelType > > create(preprocessing::SparseMultiObjectivePreprocessorResult< ModelType > const &preprocessorResult)
A bit vector that is internally represented as a vector of 64-bit values.
uint64_t getNextSetIndex(uint64_t startingIndex) const
Retrieves the index of the bit that is the next bit set to true in the bit vector.
uint64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
Halfspace< ValueType > invert() const
std::vector< ValueType > const & normalVector() const
ValueType const & offset() const
void enlarge(std::vector< ValueType > const &point)
std::vector< ValueType > const & lowerBounds() const
std::shared_ptr< Polytope< ValueType > > asPolytope() const
std::vector< ValueType > const & upperBounds() const
static std::shared_ptr< Polytope< ValueType > > createDownwardClosure(std::vector< Point > const &points)
Creates the downward closure of the given points (i.e., the set { x | ex.
static std::shared_ptr< Polytope< ValueType > > createUniversalPolytope()
Creates the universal polytope (i.e., the set R^n)
static std::shared_ptr< Polytope< ValueType > > createEmptyPolytope()
Creates the empty polytope (i.e., emptyset)
#define STORM_LOG_WARN(message)
#define STORM_LOG_DEBUG(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_ERROR_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
#define STORM_PRINT_AND_LOG(message)
std::vector< GeometryValueType > transformObjectiveValuesToOriginal(std::vector< Objective< ValueType > > objectives, std::vector< GeometryValueType > const &point)
std::shared_ptr< storm::storage::geometry::Polytope< GeometryValueType > > transformObjectivePolytopeToOriginal(std::vector< Objective< ValueType > > objectives, std::shared_ptr< storm::storage::geometry::Polytope< GeometryValueType > > const &polytope)
bool constexpr minimize(OptimizationDirection d)
T dotProduct(std::vector< T > const &firstOperand, std::vector< T > const &secondOperand)
Computes the dot product (aka scalar product) and returns the result.
std::string toString(std::vector< ValueType > const &vector)
Output vector as string.
void scaleVectorInPlace(std::vector< ValueType1 > &target, ValueType2 const &factor)
Multiplies each element of the given vector with the given factor and writes the result into the vect...
bool isZero(ValueType const &a)
std::optional< storm::storage::Scheduler< typename SparseModelType::ValueType > > scheduler
WeightVector weightVector