Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
Polytope.cpp
Go to the documentation of this file.
2
8
9namespace storm {
10namespace storage {
11namespace geometry {
12
13template<typename ValueType>
14std::shared_ptr<Polytope<ValueType>> Polytope<ValueType>::create(std::vector<storm::storage::geometry::Halfspace<ValueType>> const& halfspaces) {
15 return create(halfspaces, boost::none);
16}
17
18template<typename ValueType>
19std::shared_ptr<Polytope<ValueType>> Polytope<ValueType>::create(std::vector<Point> const& points) {
20 return create(boost::none, points);
21}
22
23template<typename ValueType>
24std::shared_ptr<Polytope<ValueType>> Polytope<ValueType>::createUniversalPolytope() {
25 return create(std::vector<Halfspace<ValueType>>(), boost::none);
26}
27
28template<typename ValueType>
29std::shared_ptr<Polytope<ValueType>> Polytope<ValueType>::createEmptyPolytope() {
30 return create(boost::none, std::vector<Point>());
31}
32
33template<typename ValueType>
34std::shared_ptr<Polytope<ValueType>> Polytope<ValueType>::create(boost::optional<std::vector<Halfspace<ValueType>>> const& halfspaces,
35 boost::optional<std::vector<Point>> const& points) {
36 return NativePolytope<ValueType>::create(halfspaces, points);
37}
38
39template<typename ValueType>
40std::shared_ptr<Polytope<ValueType>> Polytope<ValueType>::createDownwardClosure(std::vector<Point> const& points) {
41 if (points.empty()) {
42 // In this case, the downwardclosure is empty
43 return createEmptyPolytope();
44 }
45 // Reduce this call to a more general method
46 storm::storage::BitVector dimensions(points.front().size(), true);
47 return createSelectiveDownwardClosure(points, dimensions);
48}
49
50template<typename ValueType>
51std::shared_ptr<Polytope<ValueType>> Polytope<ValueType>::createSelectiveDownwardClosure(std::vector<Point> const& points,
52 storm::storage::BitVector const& selectedDimensions) {
53 if (points.empty()) {
54 // In this case, the downwardclosure is empty
55 return createEmptyPolytope();
56 }
57 if (selectedDimensions.empty()) {
58 return create(points);
59 }
60 assert(points.front().size() == selectedDimensions.size());
61
62 std::vector<Halfspace<ValueType>> halfspaces;
63 // We build the convex hull of the given points.
64 // However, auxiliary points (that will always be in the selective downward closure) are added.
65 // Then, the halfspaces of the resulting polytope are a superset of the halfspaces of the downward closure.
66 std::vector<Point> auxiliaryPoints = points;
67 auxiliaryPoints.reserve(auxiliaryPoints.size() * (1 + selectedDimensions.getNumberOfSetBits()));
68 for (auto const& point : points) {
69 for (auto dim : selectedDimensions) {
70 auxiliaryPoints.push_back(point);
71 auxiliaryPoints.back()[dim] -= storm::utility::one<ValueType>();
72 }
73 }
74 std::vector<Halfspace<ValueType>> auxiliaryHalfspaces = create(auxiliaryPoints)->getHalfspaces();
75 // The downward closure is obtained by erasing the halfspaces for which the normal vector is negative for one of the selected dimensions.
76 for (auto& h : auxiliaryHalfspaces) {
77 bool allGreaterEqZero = true;
78 for (auto dim : selectedDimensions) {
79 allGreaterEqZero &= (h.normalVector()[dim] >= storm::utility::zero<ValueType>());
80 }
81 if (allGreaterEqZero) {
82 halfspaces.push_back(std::move(h));
83 }
84 }
85 return create(halfspaces);
86}
87
88template<typename ValueType>
90 // Intentionally left empty
91}
92
93template<typename ValueType>
95 // Intentionally left empty
96}
97
98template<>
99std::vector<typename Polytope<storm::RationalNumber>::Point> Polytope<storm::RationalNumber>::getVerticesInClockwiseOrder() const {
100 std::vector<Point> vertices = getVertices();
101 if (vertices.size() <= 2) {
102 // In this case, every ordering is clockwise
103 return vertices;
104 }
105 STORM_LOG_THROW(vertices.front().size() == 2, storm::exceptions::IllegalFunctionCallException,
106 "Getting Vertices in clockwise order is only possible for a 2D-polytope.");
107
108 std::vector<storm::storage::BitVector> neighborsOfVertices(vertices.size(), storm::storage::BitVector(vertices.size(), false));
109 std::vector<Halfspace<storm::RationalNumber>> halfspaces = getHalfspaces();
110 for (auto const& h : halfspaces) {
111 storm::storage::BitVector verticesOnHalfspace(vertices.size(), false);
112 for (uint_fast64_t v = 0; v < vertices.size(); ++v) {
113 if (h.isPointOnBoundary(vertices[v])) {
114 verticesOnHalfspace.set(v);
115 }
116 }
117 for (auto v : verticesOnHalfspace) {
118 neighborsOfVertices[v] |= verticesOnHalfspace;
119 neighborsOfVertices[v].set(v, false);
120 }
121 }
122
123 std::vector<Point> result;
124 result.reserve(vertices.size());
125 storm::storage::BitVector unprocessedVertices(vertices.size(), true);
126
127 uint_fast64_t currentVertex = 0;
128 for (uint_fast64_t v = 1; v < vertices.size(); ++v) {
129 if (vertices[v].front() < vertices[currentVertex].front()) {
130 currentVertex = v;
131 }
132 }
133 STORM_LOG_ASSERT(neighborsOfVertices[currentVertex].getNumberOfSetBits() == 2,
134 "For 2D Polytopes with at least 3 vertices, each vertex should have exactly 2 neighbors");
135 uint_fast64_t firstNeighbor = neighborsOfVertices[currentVertex].getNextSetIndex(0);
136 uint_fast64_t secondNeighbor = neighborsOfVertices[currentVertex].getNextSetIndex(firstNeighbor + 1);
137 uint_fast64_t previousVertex = vertices[firstNeighbor].back() <= vertices[secondNeighbor].back() ? firstNeighbor : secondNeighbor;
138 do {
139 unprocessedVertices.set(currentVertex, false);
140 result.push_back(std::move(vertices[currentVertex]));
141
142 STORM_LOG_ASSERT(neighborsOfVertices[currentVertex].getNumberOfSetBits() == 2,
143 "For 2D Polytopes with at least 3 vertices, each vertex should have exactly 2 neighbors");
144 firstNeighbor = neighborsOfVertices[currentVertex].getNextSetIndex(0);
145 secondNeighbor = neighborsOfVertices[currentVertex].getNextSetIndex(firstNeighbor + 1);
146 uint_fast64_t nextVertex = firstNeighbor != previousVertex ? firstNeighbor : secondNeighbor;
147 previousVertex = currentVertex;
148 currentVertex = nextVertex;
149 } while (!unprocessedVertices.empty());
150
151 return result;
152}
153
154template<typename ValueType>
155std::vector<typename Polytope<ValueType>::Point> Polytope<ValueType>::getVerticesInClockwiseOrder() const {
156 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Functionality not implemented.");
157 // Note that the implementation for RationalNumber above only works for exact ValueType since
158 // checking whether the distance between halfspace and point is zero is problematic otherwise.
159 return std::vector<Point>();
160}
161
162template<typename ValueType>
163std::shared_ptr<Polytope<ValueType>> Polytope<ValueType>::shift(Point const& b) const {
164 // perform an affine transformation with identity matrix
165 std::vector<Point> idMatrix(b.size(), Point(b.size(), storm::utility::zero<ValueType>()));
166 for (uint64_t i = 0; i < b.size(); ++i) {
167 idMatrix[i][i] = storm::utility::one<ValueType>();
168 }
169 return affineTransformation(idMatrix, b);
170}
171
172template<typename ValueType>
173std::vector<std::shared_ptr<Polytope<ValueType>>> Polytope<ValueType>::setMinus(std::shared_ptr<Polytope<ValueType>> const& rhs) const {
174 std::vector<std::shared_ptr<Polytope<ValueType>>> result;
175 auto rhsHalfspaces = rhs->getHalfspaces();
176 std::shared_ptr<Polytope<ValueType>> remaining = nullptr;
177 for (auto const& h : rhsHalfspaces) {
178 Polytope<ValueType> const& ref = (remaining == nullptr) ? *this : *remaining;
179 auto next = ref.intersection(h.invert());
180 if (!next->isEmpty()) {
181 result.push_back(next);
182 }
183 remaining = ref.intersection(h);
184 if (remaining->isEmpty()) {
185 break;
186 }
187 }
188 return result;
189}
190
191template<typename ValueType>
192std::shared_ptr<Polytope<ValueType>> Polytope<ValueType>::downwardClosure() const {
193 return createDownwardClosure(this->getVertices());
194}
195
196template<typename ValueType>
197std::vector<storm::expressions::Variable> Polytope<ValueType>::declareVariables(storm::expressions::ExpressionManager& manager,
198 std::string const& namePrefix) const {
199 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Functionality not implemented for this polytope implementation.");
200 std::vector<storm::expressions::Variable> result;
201 return result;
202}
203
204template<typename ValueType>
205std::vector<storm::expressions::Expression> Polytope<ValueType>::getConstraints(storm::expressions::ExpressionManager const& manager,
206 std::vector<storm::expressions::Variable> const& variables) const {
207 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Functionality not implemented for this polytope implementation.");
208 std::vector<storm::expressions::Expression> result;
209 return result;
210}
211
212template<typename ValueType>
213template<typename TargetType>
214std::shared_ptr<Polytope<TargetType>> Polytope<ValueType>::convertNumberRepresentation() const {
215 if (isEmpty()) {
217 }
218 auto halfspaces = getHalfspaces();
219 std::vector<Halfspace<TargetType>> halfspacesPrime;
220 halfspacesPrime.reserve(halfspaces.size());
221 for (auto const& h : halfspaces) {
222 halfspacesPrime.emplace_back(storm::utility::vector::convertNumericVector<TargetType>(h.normalVector()),
223 storm::utility::convertNumber<TargetType>(h.offset()));
224 }
225
226 return Polytope<TargetType>::create(halfspacesPrime);
227}
228
229template<typename ValueType>
230std::string Polytope<ValueType>::toString(bool numbersAsDouble) const {
231 auto halfspaces = this->getHalfspaces();
232 std::stringstream stream;
233 stream << "Polytope with " << halfspaces.size() << " Halfspaces" << (halfspaces.empty() ? "" : ":") << '\n';
234 for (auto const& h : halfspaces) {
235 stream << " " << h.toString(numbersAsDouble) << '\n';
236 }
237 return stream.str();
238}
239
240template<typename ValueType>
242 return false;
243}
244
245template<typename ValueType>
246std::shared_ptr<Polytope<ValueType>> Polytope<ValueType>::clean() {
247 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "functionality not implemented for this polytope type.");
248 return nullptr;
249}
250
251template class Polytope<double>;
252template std::shared_ptr<Polytope<double>> Polytope<double>::convertNumberRepresentation() const;
253
255template std::shared_ptr<Polytope<double>> Polytope<storm::RationalNumber>::convertNumberRepresentation() const;
256template std::shared_ptr<Polytope<storm::RationalNumber>> Polytope<double>::convertNumberRepresentation() const;
257template std::shared_ptr<Polytope<storm::RationalNumber>> Polytope<storm::RationalNumber>::convertNumberRepresentation() const;
258} // namespace geometry
259} // namespace storage
260} // namespace storm
This class is responsible for managing a set of typed variables and all expressions using these varia...
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
uint64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
size_t size() const
Retrieves the number of bits this bit vector can store.
static std::shared_ptr< Polytope< ValueType > > create(boost::optional< std::vector< Halfspace< ValueType > > > const &halfspaces, boost::optional< std::vector< Point > > const &points)
Creates a NativePolytope from the given halfspaces or points.
std::vector< ValueType > Point
Definition Polytope.h:19
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.
Definition Polytope.cpp:40
virtual std::vector< Point > getVerticesInClockwiseOrder() const
Returns the vertices of this 2D-polytope in clockwise order.
Definition Polytope.cpp:155
std::vector< std::shared_ptr< Polytope< ValueType > > > setMinus(std::shared_ptr< Polytope< ValueType > > const &rhs) const
Computes the set {x \in this | x \notin rhs}.
Definition Polytope.cpp:173
static std::shared_ptr< Polytope< ValueType > > create(std::vector< Halfspace< ValueType > > const &halfspaces)
Creates a polytope from the given halfspaces.
virtual std::vector< storm::expressions::Expression > getConstraints(storm::expressions::ExpressionManager const &manager, std::vector< storm::expressions::Variable > const &variables) const
Returns the constrains defined by this polytope as an expression over the given variables.
Definition Polytope.cpp:205
virtual std::shared_ptr< Polytope< ValueType > > downwardClosure() const
Returns the downward closure of this, i.e., the set { x | ex.
Definition Polytope.cpp:192
virtual bool isNativePolytope() const
Definition Polytope.cpp:241
virtual std::shared_ptr< Polytope< ValueType > > clean()
Performs cleaning operations, e.g., deleting redundant halfspaces.
Definition Polytope.cpp:246
static std::shared_ptr< Polytope< ValueType > > createUniversalPolytope()
Creates the universal polytope (i.e., the set R^n)
Definition Polytope.cpp:24
virtual std::string toString(bool numbersAsDouble=false) const
Definition Polytope.cpp:230
std::shared_ptr< Polytope< TargetType > > convertNumberRepresentation() const
converts the intern number representation of the polytope to the given target type
Definition Polytope.cpp:214
static std::shared_ptr< Polytope< ValueType > > createEmptyPolytope()
Creates the empty polytope (i.e., emptyset)
Definition Polytope.cpp:29
virtual std::shared_ptr< Polytope< ValueType > > intersection(std::shared_ptr< Polytope< ValueType > > const &rhs) const =0
Intersects this polytope with rhs and returns the result.
static std::shared_ptr< Polytope< ValueType > > createSelectiveDownwardClosure(std::vector< Point > const &points, storm::storage::BitVector const &selectedDimensions)
Creates the downward closure of the given points but only with respect to the selected dimensions,...
Definition Polytope.cpp:51
std::shared_ptr< Polytope< ValueType > > shift(Point const &b) const
Returns the Polytope described by the set {x+b | x \in this}.
Definition Polytope.cpp:163
virtual std::vector< storm::expressions::Variable > declareVariables(storm::expressions::ExpressionManager &manager, std::string const &namePrefix) const
Declares one variable for each dimension and returns the obtained variables.
Definition Polytope.cpp:197
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30