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