7 changed files with 547 additions and 69 deletions
			
			
		- 
					15src/adapters/HyproAdapter.h
- 
					19src/storage/geometry/Halfspace.h
- 
					77src/storage/geometry/Hyperrectangle.h
- 
					195src/storage/geometry/HyproPolytope.cpp
- 
					124src/storage/geometry/HyproPolytope.h
- 
					106src/storage/geometry/Polytope.cpp
- 
					80src/storage/geometry/Polytope.h
| @ -0,0 +1,77 @@ | |||
| #ifndef STORM_STORAGE_GEOMETRY_HYPERRECTANGLE_H_ | |||
| #define STORM_STORAGE_GEOMETRY_HYPERRECTANGLE_H_ | |||
| 
 | |||
| #include <iostream> | |||
| #include <iomanip> | |||
| 
 | |||
| #include "src/utility/macros.h" | |||
| #include "src/storage/geometry/Polytope.h" | |||
| #include "src/storage/geometry/Halfspace.h" | |||
| #include "src/exceptions/InvalidArgumentException" | |||
| 
 | |||
| namespace storm { | |||
|     namespace storage { | |||
|         namespace geometry { | |||
|              | |||
|             /*  | |||
|              * This class represents a hyperrectangle, i.e., the intersection of finitely many intervals | |||
|              */ | |||
|               | |||
|             template <typename ValueType> | |||
|             class Hyperrectangle { | |||
|                  | |||
|             public: | |||
|                  | |||
|                 Hyperrectangle(std::vector<ValueType> const& lowerBounds, std::vector<ValueType> const& upperBounds) : mLowerBounds(lowerBounds), mUpperBounds(upperBounds) { | |||
|                     STORM_LOG_THROW(lowerBounds.size() == upperBounds.size(), storm::exceptions::InvalidArgumentException, "Tried to construct a hyperrectangle but the number of given lower bounds does not equal the number of given upper bounds."); | |||
|                 } | |||
|                  | |||
|                 Hyperrectangle(std::vector<ValueType>&& lowerBounds, std::vector<ValueType>&& upperBounds) : mLowerBounds(lowerBounds), mUpperBounds(upperBounds) { | |||
|                     STORM_LOG_THROW(lowerBounds.size() == upperBounds.size(), storm::exceptions::InvalidArgumentException, "Tried to construct a hyperrectangle but the number of given lower bounds does not equal the number of given upper bounds."); | |||
|                 } | |||
|                  | |||
|                 std::vector<ValueType> const& lowerBounds() const { | |||
|                     return mLowerBounds; | |||
|                 } | |||
|                  | |||
|                 std::vector<ValueType>& lowerBounds(){ | |||
|                     return mLowerBounds; | |||
|                 } | |||
|                  | |||
|                 std::vector<ValueType> const& upperBounds() const { | |||
|                     return mUpperBounds; | |||
|                 } | |||
|                  | |||
|                 std::vector<ValueType>& upperBounds(){ | |||
|                     return mUpperBounds; | |||
|                 } | |||
|                  | |||
|                 std::shared_ptr<Polytope<ValueType>> asPolytope() const { | |||
|                     STORM_LOG_THROW(lowerBounds.size() == upperBounds.size(), storm::exceptions::InvalidArgumentException, "Tried to construct a polytope form a hyperrectangle but the numbers of given lower and upper bounds do not match."); | |||
|                     std::vector<Halfspace<ValueType>> halfspaces; | |||
|                     halfspaces.reserve(2*lowerBounds.size()); | |||
|                     for(uint_fast64_t i = 0; i<lowerBounds.size(); ++i) { | |||
|                         std::vector<ValueType> direction(lowerBounds.size(), storm::utility::zero<ValueType>()); | |||
|                         direction[i] = -storm::utility::one<ValueType>(); | |||
|                         ValueType offset = -lowerBounds()[i]; | |||
|                         halfspaces.emplace_back(std::move(direction), std::move(offset)); | |||
|                          | |||
|                         direction = std::vector<ValueType>(lowerBounds.size(), storm::utility::zero<ValueType>()); | |||
|                         direction[i] = storm::utility::one<ValueType>(); | |||
|                         offset = upperBounds()[i]; | |||
|                         halfspaces.emplace_back(std::move(direction), std::move(offset)); | |||
|                     } | |||
|                     return Polytope<ValueType>::create(halfspaces); | |||
|                 } | |||
|                  | |||
|             private: | |||
|                  | |||
|                 std::vector<ValueType> mLowerBounds; | |||
|                 std::vector<ValueType> mUpperBounds; | |||
|                  | |||
|             }; | |||
|         } | |||
|     } | |||
| } | |||
| 
 | |||
| #endif /* STORM_STORAGE_GEOMETRY_HYPERRECTANGLE_H_ */ | |||
| @ -0,0 +1,195 @@ | |||
| #include "src/storage/geometry/HyproPolytope.h"
 | |||
| 
 | |||
| #include "src/utility/macros.h"
 | |||
| #include "src/exceptions/InvalidArgumentException.h"
 | |||
| #include "src/exceptions/UnexpectedException.h"
 | |||
| 
 | |||
| namespace storm { | |||
|     namespace storage { | |||
|         namespace geometry { | |||
|              | |||
|             template <typename ValueType> | |||
|             HyproPolytope<ValueType>::HyproPolytope(std::vector<Halfspace<ValueType>> const& halfspaces) { | |||
|                 if(halfspaces.empty()){ | |||
|                     internPolytope = HyproPolytopeType(); | |||
|                 } else { | |||
|                     std::vector<hypro::Halfspace<ValueType>> hyproHalfspaces; | |||
|                     hyproHalfspaces.reserve(halfspaces.size()); | |||
|                     for(auto& h : halfspaces) { | |||
|                         hyproHalfspaces.emplace_back(storm::adapters::toHypro(h)); | |||
|                     } | |||
|                     internPolytope = HyproPolytopeType(std::move(hyproHalfspaces)); | |||
|                 } | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             HyproPolytope<ValueType>::HyproPolytope(std::vector<Point> const& points) { | |||
|                 if(points.empty()){ | |||
|                     internPolytope = HyproPolytopeType::Empty(); | |||
|                 } else { | |||
|                     std::vector<hypro::Point<ValueType>> hyproPoints; | |||
|                     hyproPoints.reserve(points.size()); | |||
|                     for(auto const& p : points){ | |||
|                         hyproPoints.emplace_back(storm::adapters::toHypro(p)); | |||
|                     } | |||
|                     internPolytope = HyproPolytopeType(std::move(hyproPoints)); | |||
|                 } | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             std::shared_ptr<Polytope<ValueType>> HyproPolytope<ValueType>::create(boost::optional<std::vector<Halfspace<ValueType>>> const& halfspaces, | |||
|                                                                              boost::optional<std::vector<Point>> const& points) { | |||
|                 if(halfspaces) { | |||
|                     STORM_LOG_WARN_COND(!points, "Creating a HyproPolytope where halfspaces AND points are given. The points will be ignored."); | |||
|                     return std::make_shared<HyproPolytope<ValueType>>(*halfspaces); | |||
|                 } else if(points) { | |||
|                     return std::make_shared<HyproPolytope<ValueType>>(*points); | |||
|                 } | |||
|                 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Creating a HyproPolytope but no representation was given."); | |||
|                 return nullptr; | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             HyproPolytope<ValueType>::HyproPolytope(HyproPolytope<ValueType> const& other) : internPolytope(other.internPolytope) { | |||
|                 // Intentionally left empty
 | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             HyproPolytope<ValueType>::HyproPolytope(HyproPolytope<ValueType>&& other) : internPolytope(std::move(other.internPolytope)) { | |||
|                 // Intentionally left empty
 | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             HyproPolytope<ValueType>::HyproPolytope(HyproPolytopeType const& p) : internPolytope(p) { | |||
|                 // Intentionally left empty
 | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             HyproPolytope<ValueType>::HyproPolytope(HyproPolytopeType&& p) : internPolytope(p) { | |||
|                 // Intentionally left empty
 | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             HyproPolytope<ValueType>::~HyproPolytope() { | |||
|                 // Intentionally left empty
 | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             std::vector<typename Polytope<ValueType>::Point> HyproPolytope<ValueType>::getVertices() const { | |||
|                 std::vector<hypro::Point<ValueType>> hyproVertices = internPolytope.vertices(); | |||
|                 std::vector<Point> result; | |||
|                 result.reserve(hyproVertices.size()); | |||
|                 for(auto const& p : hyproVertices) { | |||
|                     result.push_back(storm::adapters::fromHypro(p.rawCoordinates())); | |||
|                 } | |||
|                 return result; | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             std::vector<Halfspace<ValueType>> HyproPolytope<ValueType>::getHalfspaces() const { | |||
|                 std::vector<hypro::Halfspace<ValueType>> hyproHalfspaces = internPolytope.constraints(); | |||
|                 std::vector<Halfspace<ValueType>> result; | |||
|                 result.reserve(hyproHalfspaces.size()); | |||
|                 for(auto const& h : hyproHalfspaces) { | |||
|                     result.push_back(storm::adapters::fromHypro(h)); | |||
|                 } | |||
|                 return result; | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             bool HyproPolytope<ValueType>::isEmpty() const { | |||
|                 return internPolytope.empty(); | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             bool HyproPolytope<ValueType>::isUniversal() const { | |||
|                 return internPolytope.constraints().empty(); | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             bool HyproPolytope<ValueType>::contains(Point const& point) const{ | |||
|                 return internPolytope.contains(storm::adapters::toHypro(point)); | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             bool HyproPolytope<ValueType>::contains(std::shared_ptr<Polytope<ValueType>> const& other) const { | |||
|                 STORM_LOG_THROW(other->isHyproPolytope(), storm::exceptions::InvalidArgumentException, "Invoked operation between a HyproPolytope and a different polytope implementation. This is not supported"); | |||
|                 return internPolytope.contains(other->asHyproPolytope().internPolytope); | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             std::shared_ptr<Polytope<ValueType>> HyproPolytope<ValueType>::intersection(std::shared_ptr<Polytope<ValueType>> const& rhs) const{ | |||
|                 STORM_LOG_THROW(rhs->isHyproPolytope(), storm::exceptions::InvalidArgumentException, "Invoked operation between a HyproPolytope and a different polytope implementation. This is not supported"); | |||
|                 return std::make_shared<HyproPolytope<ValueType>>(internPolytope.intersect(rhs->asHyproPolytope().internPolytope)); | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             std::shared_ptr<Polytope<ValueType>> HyproPolytope<ValueType>::intersection(Halfspace<ValueType> const& halfspace) const{ | |||
|                 HyproPolytopeType result(internPolytope); | |||
|                 result.insert(storm::adapters::toHypro(halfspace)); | |||
|                 return std::make_shared<HyproPolytope<ValueType>>(std::move(result)); | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             std::shared_ptr<Polytope<ValueType>> HyproPolytope<ValueType>::convexUnion(std::shared_ptr<Polytope<ValueType>> const& rhs) const{ | |||
|                 STORM_LOG_THROW(rhs->isHyproPolytope(), storm::exceptions::InvalidArgumentException, "Invoked operation between a HyproPolytope and a different polytope implementation. This is not supported"); | |||
|                 return std::make_shared<HyproPolytope<ValueType>>(internPolytope.unite(rhs->asHyproPolytope().internPolytope)); | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             std::shared_ptr<Polytope<ValueType>> HyproPolytope<ValueType>::minkowskiSum(std::shared_ptr<Polytope<ValueType>> const& rhs) const{ | |||
|                 STORM_LOG_THROW(rhs->isHyproPolytope(), storm::exceptions::InvalidArgumentException, "Invoked operation between a HyproPolytope and a different polytope implementation. This is not supported"); | |||
|                 return std::make_shared<HyproPolytope<ValueType>>(internPolytope.minkowskiSum(rhs->asHyproPolytope().internPolytope)); | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             std::shared_ptr<Polytope<ValueType>> HyproPolytope<ValueType>::downwardClosure(boost::optional<Point> const& upperBounds) const { | |||
|                 if(this->isUniversal() || this->isEmpty()) { | |||
|                     // In these cases, the polytope does not change, i.e., we return a copy of this
 | |||
|                     return std::make_shared<HyproPolytope<ValueType>>(internPolytope); | |||
|                 } | |||
|                 // Only keep the halfspaces where all entries of the normal vector are non-negative
 | |||
|                 std::vector<hypro::Halfspace<ValueType>> halfspaces; | |||
|                 for(auto& h : internPolytope.constraints()){ | |||
|                     if((h.normal().array() >= storm::utility::zero<ValueType>()).all()){ | |||
|                         halfspaces.push_back(h); | |||
|                     } | |||
|                 } | |||
|                 // Add Halfspaces to bound the polytope in each (positive) direction
 | |||
|                 for(uint_fast64_t dim = 0; dim < internPolytope.dimension(); ++dim){ | |||
|                     hypro::vector_t<ValueType> direction = hypro::vector_t<ValueType>::Zero(dim); | |||
|                     direction(dim) = storm::utility::one<ValueType>(); | |||
|                     if(upperBounds){ | |||
|                         ValueType upperBound = (*upperBounds)[dim]; | |||
|                         halfspaces.emplace_back(std::move(direction), std::move(upperBound)); | |||
|                     } else { | |||
|                         // Compute max{x_dim | x \in P }
 | |||
|                         hypro::EvaluationResult<ValueType> evalRes = internPolytope.evaluate(direction); | |||
|                         switch (evalRes.errorCode) { | |||
|                             case hypro::SOLUTION::FEAS: | |||
|                                 halfspaces.emplace_back(std::move(direction), std::move(evalRes.supportValue)); | |||
|                                 break; | |||
|                             case hypro::SOLUTION::INFTY: | |||
|                                 // if this polytope is not bounded in the current direction, no halfspace needs to be added
 | |||
|                                 break; | |||
|                             default: | |||
|                                 // there should never be an infeasible solution as we already excluded the empty polytope.
 | |||
|                                 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unexpected eror code for Polytope evaluation"); | |||
|                                 break; | |||
|                         } | |||
|                     } | |||
|                 } | |||
|                 return std::make_shared<HyproPolytope<ValueType>>(HyproPolytopeType(std::move(halfspaces))); | |||
|             } | |||
|              | |||
|             template <typename ValueType> | |||
|             bool HyproPolytope<ValueType>::isHyproPolytope() const { | |||
|                 return true; | |||
|             } | |||
|              | |||
| #ifdef STORM_HAVE_CARL
 | |||
|             template class HyproPolytope<storm::RationalNumber>; | |||
| #endif
 | |||
|         } | |||
|     } | |||
| } | |||
| @ -0,0 +1,124 @@ | |||
| #ifndef STORM_STORAGE_GEOMETRY_HYPROPOLYTOPE_H_ | |||
| #define STORM_STORAGE_GEOMETRY_HYPROPOLYTOPE_H_ | |||
| 
 | |||
| #include "src/storage/geometry/Polytope.h" | |||
| #include "src/adapters/HyproAdapter.h" | |||
| 
 | |||
| #ifdef STORM_HAVE_HYPRO | |||
| 
 | |||
| namespace storm { | |||
|     namespace storage { | |||
|         namespace geometry { | |||
|              | |||
|             template <typename ValueType> | |||
|             class HyproPolytope : public Polytope<ValueType> { | |||
|             public: | |||
|                  | |||
|                 typedef typename Polytope<ValueType>::Point Point; | |||
|                 typedef hypro::HPolytope<ValueType> HyproPolytopeType; | |||
|                  | |||
|                 /*! | |||
|                  * Creates a HyproPolytope from the given halfspaces or points. | |||
|                  * If both representations are given, one of them might be ignored | |||
|                  */ | |||
|                 static std::shared_ptr<Polytope<ValueType>> create(boost::optional<std::vector<Halfspace<ValueType>>> const& halfspaces, | |||
|                                                                    boost::optional<std::vector<Point>> const& points); | |||
|                  | |||
|                 /*! | |||
|                  * Creates a HyproPolytope from the given halfspaces | |||
|                  * The resulting polytope is defined as the intersection of the halfspaces. | |||
|                  */ | |||
|                 HyproPolytope(std::vector<Halfspace<ValueType>> const& halfspaces); | |||
|                  | |||
|                 /*! | |||
|                  * Creates a HyproPolytope from the given points. | |||
|                  * The resulting polytope is defined as the convex hull of the points' | |||
|                  */ | |||
|                 HyproPolytope(std::vector<Point> const& points); | |||
|                  | |||
|                 /*! | |||
|                  * Copy and move constructors | |||
|                  */ | |||
|                 HyproPolytope(HyproPolytope<ValueType> const& other); | |||
|                 HyproPolytope(HyproPolytope<ValueType>&& other); | |||
|                  | |||
|                 /*! | |||
|                  * Construction from a plain hypro polytope | |||
|                  */ | |||
|                 HyproPolytope(HyproPolytopeType const& polytope); | |||
|                 HyproPolytope(HyproPolytopeType&& polytope); | |||
|                  | |||
|                 ~HyproPolytope(); | |||
| 
 | |||
|                 /*! | |||
|                  * Returns the vertices of this polytope. | |||
|                  */ | |||
|                 virtual std::vector<Point> getVertices() const override; | |||
|                  | |||
|                 /*! | |||
|                  * Returns the halfspaces of this polytope. | |||
|                  */ | |||
|                 virtual std::vector<Halfspace<ValueType>> getHalfspaces() const override; | |||
|                  | |||
|                  | |||
|                 /*! | |||
|                  * Returns whether this polytope is the empty set. | |||
|                  */ | |||
|                 virtual bool isEmpty() const override; | |||
|                  | |||
|                 /*! | |||
|                  * Returns whether this polytope is universal (i.e., equals R^n). | |||
|                  */ | |||
|                 virtual bool isUniversal() const override; | |||
|                  | |||
|                 /*! | |||
|                  * Returns true iff the given point is inside of the polytope. | |||
|                  */ | |||
|                 virtual bool contains(Point const& point) const override; | |||
|                  | |||
|                 /*! | |||
|                  * Returns true iff the given polytope is a subset of this polytope. | |||
|                  */ | |||
|                 virtual bool contains(std::shared_ptr<Polytope<ValueType>> const& other) const override; | |||
|                  | |||
|                 /*! | |||
|                  * Intersects this polytope with rhs and returns the result. | |||
|                  */ | |||
|                 virtual std::shared_ptr<Polytope<ValueType>> intersection(std::shared_ptr<Polytope<ValueType>> const& rhs) const override; | |||
|                 virtual std::shared_ptr<Polytope<ValueType>> intersection(Halfspace<ValueType> const& halfspace) const override; | |||
|                  | |||
|                 /*! | |||
|                  * Returns the convex union of this polytope and rhs. | |||
|                  */ | |||
|                 virtual std::shared_ptr<Polytope<ValueType>> convexUnion(std::shared_ptr<Polytope<ValueType>> const& rhs) const override; | |||
|                  | |||
|                 /*! | |||
|                  * Returns the minkowskiSum of this polytope and rhs. | |||
|                  */ | |||
|                 virtual std::shared_ptr<Polytope<ValueType>> minkowskiSum(std::shared_ptr<Polytope<ValueType>> const& rhs) const override; | |||
|                  | |||
|                 /*! | |||
|                  * Returns the downward closure of this, i.e., the set { x | ex. y \in P : x<=y} where P is this Polytope. | |||
|                  * Put differently, the resulting polytope corresponds to this polytope, where | |||
|                  * 1. a vector y with y_i=max{x_i | x \in P} is computed and for each i, a halfspace with offset y_i and | |||
|                  *    normal vector n (where n_i = 1 and the remaining entries are 0) is inserted. | |||
|                  * 2. all halfspaces where the normal vector has at least one negative entry are removed | |||
|                  * | |||
|                  * @param upperBounds If given, this vector is considered for y (hence, max{x_i | x i \in P does not need to be computed) | |||
|                  */ | |||
|                 virtual std::shared_ptr<Polytope<ValueType>> downwardClosure(boost::optional<Point> const& upperBounds = boost::none) const override; | |||
|              | |||
|                 virtual bool isHyproPolytope() const override; | |||
|                  | |||
|             private: | |||
|                  | |||
|                 HyproPolytopeType internPolytope; | |||
|             }; | |||
|              | |||
|         } | |||
|     } | |||
| } | |||
| 
 | |||
| #endif /* STORM_HAVE_HYPRO */ | |||
| 
 | |||
| #endif /* STORM_STORAGE_GEOMETRY_HYPROPOLYTOPE_H_ */ | |||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue