Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
QuickHull.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <unordered_map>
5
13
14namespace storm {
15namespace storage {
16namespace geometry {
17
18template<typename ValueType>
19void QuickHull<ValueType>::generateHalfspacesFromPoints(std::vector<EigenVector>& points, bool generateRelevantVerticesAndVertexSets) {
20 STORM_LOG_ASSERT(!points.empty(), "Invoked QuickHull with empty set of points.");
21 STORM_LOG_DEBUG("Invoked QuickHull on " << points.size() << " points");
22 const uint_fast64_t dimension = points.front().rows();
23
24 if (dimension == 1) {
25 handle1DPoints(points, generateRelevantVerticesAndVertexSets);
26 } else {
27 // Generate initial set of d+1 affine independent points (if such a set exists)
28 std::vector<uint_fast64_t> vertexIndices;
29 if (this->findInitialVertices(points, vertexIndices)) {
30 // compute point inside initial facet
31 EigenVector insidePoint(EigenVector::Zero(dimension));
32 for (uint_fast64_t vertexIndex : vertexIndices) {
33 insidePoint += points[vertexIndex];
34 }
35 insidePoint /= storm::utility::convertNumber<ValueType>(static_cast<uint_fast64_t>(vertexIndices.size()));
36
37 // Create the initial facets from the found vertices.
38 std::vector<Facet> facets = computeInitialFacets(points, vertexIndices, insidePoint);
39
40 // Enlarge the mesh
41 storm::storage::BitVector currentFacets(facets.size(), true);
42 this->extendMesh(points, facets, currentFacets, insidePoint);
43
44 // Finally retrieve the resulting constrants
45 this->getPolytopeFromMesh(points, facets, currentFacets, generateRelevantVerticesAndVertexSets);
46 STORM_LOG_DEBUG("QuickHull invokation yielded " << resultMatrix.rows() << " constraints");
47 } else {
48 // The points are affine dependent. This special case needs to be handled accordingly.
49 handleAffineDependentPoints(points, generateRelevantVerticesAndVertexSets);
50 }
51 }
52}
53
54template<typename ValueType>
56 return this->resultMatrix;
57}
58
59template<typename ValueType>
61 return this->resultVector;
62}
63
64template<typename ValueType>
65std::vector<typename QuickHull<ValueType>::EigenVector>& QuickHull<ValueType>::getRelevantVertices() {
66 return this->relevantVertices;
67}
68
69template<typename ValueType>
70std::vector<std::vector<uint_fast64_t>>& QuickHull<ValueType>::getVertexSets() {
71 return this->vertexSets;
72}
73
74template<typename ValueType>
75void QuickHull<ValueType>::handle1DPoints(std::vector<EigenVector>& points, bool generateRelevantVerticesAndVertexSets) {
76 ValueType minValue = points.front()(0);
77 ValueType maxValue = points.front()(0);
78 uint_fast64_t minIndex = 0;
79 uint_fast64_t maxIndex = 0;
80 for (uint_fast64_t pointIndex = 1; pointIndex < points.size(); ++pointIndex) {
81 ValueType const& pointValue = points[pointIndex](0);
82 if (pointValue < minValue) {
83 minValue = pointValue;
84 minIndex = pointIndex;
85 }
86 if (pointValue > maxValue) {
87 maxValue = pointValue;
88 maxIndex = pointIndex;
89 }
90 }
91 resultMatrix = EigenMatrix(2, 1);
92 resultMatrix(0, 0) = -storm::utility::one<ValueType>();
93 resultMatrix(1, 0) = storm::utility::one<ValueType>();
94 resultVector = EigenVector(2);
95 resultVector(0) = -minValue;
96 resultVector(1) = maxValue;
97 if (generateRelevantVerticesAndVertexSets) {
98 relevantVertices.push_back(points[minIndex]);
99 std::vector<uint_fast64_t> minVertexSet(1, 0);
100 vertexSets.push_back(std::move(minVertexSet));
101 if (minIndex != maxIndex && points[minIndex] != points[maxIndex]) {
102 relevantVertices.push_back(points[maxIndex]);
103 std::vector<uint_fast64_t> maxVertexSet(1, 1);
104 vertexSets.push_back(std::move(maxVertexSet));
105 } else {
106 vertexSets.push_back(vertexSets.front());
107 }
108 }
109}
110
111template<typename ValueType>
112bool QuickHull<ValueType>::affineFilter(std::vector<uint_fast64_t> const& subset, uint_fast64_t const& item, std::vector<EigenVector> const& points) {
113 EigenMatrix vectorMatrix(points[item].rows() + 1, subset.size() + 1);
114 for (uint_fast64_t i = 0; i < subset.size(); ++i) {
115 vectorMatrix.col(i) << points[subset[i]], storm::utility::one<ValueType>();
116 }
117 vectorMatrix.col(subset.size()) << points[item], storm::utility::one<ValueType>();
118 return (vectorMatrix.fullPivLu().rank() > (Eigen::Index)subset.size());
119}
120
121template<typename ValueType>
122void QuickHull<ValueType>::handleAffineDependentPoints(std::vector<EigenVector>& points, bool generateRelevantVerticesAndVertexSets) {
123 bool pointsAffineDependent = true;
124 std::vector<std::pair<EigenVector, ValueType>> additionalConstraints;
125 while (pointsAffineDependent) {
126 // get one hyperplane that holds all points
127 const uint_fast64_t dimension = points.front().rows();
128 EigenVector refPoint = points.front();
129 EigenVector normal;
130 if (points.size() == 1) {
131 normal.resize(dimension);
132 normal(0) = storm::utility::one<ValueType>();
133 } else {
134 EigenMatrix constraints(points.size() - 1, dimension);
135 for (unsigned row = 1; row < points.size(); ++row) {
136 constraints.row(row - 1) = points[row] - refPoint;
137 }
138 normal = constraints.fullPivLu().kernel().col(0);
139 }
140
141 // Eigen returns the column vector 0...0 if the kernel is empty (i.e., there is no such hyperplane)
142 if (normal.isZero()) {
143 pointsAffineDependent = false;
144 } else {
145 points.push_back(refPoint + normal);
146 ValueType offset = normal.dot(refPoint);
147 additionalConstraints.emplace_back(std::move(normal), std::move(offset));
148 }
149 }
150 // Now the points are affine independent so we can relaunch the procedure
151 generateHalfspacesFromPoints(points, generateRelevantVerticesAndVertexSets);
152
153 // Add the constraints obtained above
154 uint_fast64_t numOfAdditionalConstraints = additionalConstraints.size();
155 uint_fast64_t numOfRegularConstraints = resultMatrix.rows();
156 EigenMatrix newA(numOfRegularConstraints + numOfAdditionalConstraints, resultMatrix.cols());
157 EigenVector newb(static_cast<unsigned long int>(numOfRegularConstraints + numOfAdditionalConstraints));
158 uint_fast64_t row = 0;
159 for (; row < numOfRegularConstraints; ++row) {
160 newA.row(row) = resultMatrix.row(row);
161 newb(row) = resultVector(row);
162 }
163 for (; row < numOfRegularConstraints + numOfAdditionalConstraints; ++row) {
164 newA.row(row) = std::move(additionalConstraints[row - numOfRegularConstraints].first);
165 newb(row) = additionalConstraints[row - numOfRegularConstraints].second;
166 }
167 resultMatrix = std::move(newA);
168 resultVector = std::move(newb);
169
170 // clear the additionally added points. Note that the order of the points might have changed
171 storm::storage::BitVector keptPoints(points.size(), true);
172 for (uint_fast64_t pointIndex = 0; pointIndex < points.size(); ++pointIndex) {
173 for (Eigen::Index row = 0; row < resultMatrix.rows(); ++row) {
174 if ((resultMatrix.row(row) * points[pointIndex])(0) > resultVector(row)) {
175 keptPoints.set(pointIndex, false);
176 break;
177 }
178 }
179 }
181
182 if (generateRelevantVerticesAndVertexSets) {
183 storm::storage::BitVector keptVertices(relevantVertices.size(), true);
184 for (uint_fast64_t vertexIndex = 0; vertexIndex < relevantVertices.size(); ++vertexIndex) {
185 for (Eigen::Index row = 0; row < resultMatrix.rows(); ++row) {
186 if ((resultMatrix.row(row) * relevantVertices[vertexIndex])(0) > resultVector(row)) {
187 keptVertices.set(vertexIndex, false);
188 break;
189 }
190 }
191 }
192 storm::utility::vector::filterVectorInPlace(relevantVertices, keptVertices);
193
194 STORM_LOG_WARN("Can not retrieve vertex sets for degenerated polytope (not implemented)");
195 vertexSets.clear();
196 }
197}
198
199template<typename ValueType>
200bool QuickHull<ValueType>::findInitialVertices(std::vector<EigenVector>& points, std::vector<uint_fast64_t>& verticesOfInitialPolytope) const {
201 const uint_fast64_t dimension = points.front().rows();
202 if (points.size() < dimension + 1) {
203 // not enough points to obtain a (non-degenerated) polytope
204 return false;
205 }
206
207 // We first find some good candidates to get a (hopefully) large initial mesh.
208 storm::storage::BitVector notGoodCandidates(points.size(), true);
209 for (uint_fast64_t dim = 0; dim < dimension; ++dim) {
210 if (!notGoodCandidates.empty()) {
211 uint_fast64_t minIndex = *notGoodCandidates.begin();
212 uint_fast64_t maxIndex = *notGoodCandidates.begin();
213 for (uint_fast64_t pointIndex : notGoodCandidates) {
214 if (points[minIndex](dim) > points[pointIndex](dim)) {
215 minIndex = pointIndex;
216 }
217 if (points[maxIndex](dim) < points[pointIndex](dim)) {
218 maxIndex = pointIndex;
219 }
220 }
221 notGoodCandidates.set(minIndex, false);
222 notGoodCandidates.set(maxIndex, false);
223 }
224 }
225 storm::storage::BitVector goodCandidates = ~notGoodCandidates;
226
227 // Found candidates. Now swap them to the front.
228 const uint_fast64_t numOfGoodCandidates = goodCandidates.getNumberOfSetBits();
229 for (auto goodCandidate : goodCandidates) {
230 if (goodCandidate >= numOfGoodCandidates) {
231 uint_fast64_t notGoodCandidate = *notGoodCandidates.begin();
232 STORM_LOG_ASSERT(notGoodCandidate < numOfGoodCandidates, "Not-good candidate index out of range.");
233 std::swap(points[notGoodCandidate], points[goodCandidate]);
234 notGoodCandidates.set(notGoodCandidate, false);
235 }
236 }
237
238 storm::storage::geometry::SubsetEnumerator<std::vector<EigenVector>> subsetEnum(points.size(), dimension + 1, points, affineFilter);
239 if (subsetEnum.setToFirstSubset()) {
240 verticesOfInitialPolytope = subsetEnum.getCurrentSubset();
241 return true;
242 } else {
243 return false;
244 }
245}
246
247template<typename ValueType>
248std::vector<typename QuickHull<ValueType>::Facet> QuickHull<ValueType>::computeInitialFacets(std::vector<EigenVector> const& points,
249 std::vector<uint_fast64_t> const& verticesOfInitialPolytope,
250 EigenVector const& insidePoint) const {
251 const uint_fast64_t dimension = points.front().rows();
252 STORM_LOG_ASSERT(verticesOfInitialPolytope.size() == dimension + 1, "Number of vertices does not match dimension+1.");
253 std::vector<Facet> result;
254 result.reserve(dimension + 1);
255 storm::storage::geometry::SubsetEnumerator<> subsetEnum(verticesOfInitialPolytope.size(), dimension);
256 STORM_LOG_THROW(subsetEnum.setToFirstSubset(), storm::exceptions::UnexpectedException, "Could not find an initial subset.");
257 do {
258 Facet newFacet;
259 // set the points that lie on the new facet
260 std::vector<uint_fast64_t> const& subset(subsetEnum.getCurrentSubset());
261 newFacet.points.reserve(subset.size());
262 for (uint_fast64_t i : subset) {
263 newFacet.points.push_back(verticesOfInitialPolytope[i]);
264 }
265 // neighbors: these are always the remaining facets
266 newFacet.neighbors.reserve(dimension);
267 for (uint_fast64_t i = 0; i < dimension + 1; ++i) {
268 if (i != result.size()) { // initFacets.size() will be the index of this new facet!
269 newFacet.neighbors.push_back(i);
270 }
271 }
272 // normal and offset:
273 computeNormalAndOffsetOfFacet(points, insidePoint, newFacet);
274
275 result.push_back(std::move(newFacet));
276 } while (subsetEnum.incrementSubset());
277 STORM_LOG_ASSERT(result.size() == dimension + 1, "Number of result facets does not match dimension+1.");
278 return result;
279}
280
281template<typename ValueType>
282void QuickHull<ValueType>::computeNormalAndOffsetOfFacet(std::vector<EigenVector> const& points, EigenVector const& insidePoint, Facet& facet) const {
283 const uint_fast64_t dimension = points.front().rows();
284 STORM_LOG_ASSERT(facet.points.size() == dimension, "Facet points size does not match dimension.");
285 EigenVector const& refPoint = points[facet.points.back()];
286 EigenMatrix constraints(dimension - 1, dimension);
287 for (unsigned row = 0; row < dimension - 1; ++row) {
288 constraints.row(row) = (points[facet.points[row]] - refPoint);
289 }
290 facet.normal = constraints.fullPivLu().kernel().col(0);
291 facet.offset = facet.normal.dot(refPoint);
292
293 // invert the plane if the insidePoint is not contained in it
294 if (facet.normal.dot(insidePoint) > facet.offset) {
295 facet.normal = -facet.normal;
296 facet.offset = -facet.offset;
297 }
298}
299
300template<typename ValueType>
301void QuickHull<ValueType>::extendMesh(std::vector<EigenVector>& points, std::vector<Facet>& facets, storm::storage::BitVector& currentFacets,
302 EigenVector& insidePoint) const {
303 storm::storage::BitVector currentOutsidePoints(points.size(), true);
304 // Compute initial outside Sets
305 for (uint_fast64_t facetIndex : currentFacets) {
306 computeOutsideSetOfFacet(facets[facetIndex], currentOutsidePoints, points);
307 }
308
309 for (uint_fast64_t facetCount = currentFacets.getNextSetIndex(0); facetCount != currentFacets.size();
310 facetCount = currentFacets.getNextSetIndex(facetCount + 1)) {
311 // set all points to false to get rid of points that lie within the polytope after each iteration
312 currentOutsidePoints.clear();
313 // Find a facet with a non-empty outside set
314 if (!facets[facetCount].outsideSet.empty()) {
315 uint_fast64_t numberOfNewFacets = 0;
316 // Now we compute the enlarged mesh
317 uint_fast64_t farAwayPointIndex = facets[facetCount].maxOutsidePointIndex;
318 // get Visible set from maxOutsidePoint of the current facet
319 std::set<uint_fast64_t> visibleSet = getVisibleSet(facets, facetCount, points[farAwayPointIndex]);
320 std::set<uint_fast64_t> invisibleSet = getInvisibleNeighbors(facets, visibleSet);
321 for (auto invisFacetIt = invisibleSet.begin(); invisFacetIt != invisibleSet.end(); ++invisFacetIt) {
322 for (auto visFacetIt = visibleSet.begin(); visFacetIt != visibleSet.end(); ++visFacetIt) {
323 if (std::find(facets[*invisFacetIt].neighbors.begin(), facets[*invisFacetIt].neighbors.end(), *visFacetIt) !=
324 facets[*invisFacetIt].neighbors.end()) {
325 Facet newFacet;
326 // Set points of Facet
327 newFacet.points = getCommonPoints(facets[*invisFacetIt], facets[*visFacetIt]);
328 newFacet.points.push_back(farAwayPointIndex);
329 // replace old facet index by new facet index in the current neighbor
330 replaceFacetNeighbor(facets, *visFacetIt, facets.size(), *invisFacetIt);
331 newFacet.neighbors.push_back(*invisFacetIt);
332 // Compute the normal and the offset
333 computeNormalAndOffsetOfFacet(points, insidePoint, newFacet);
334
335 // add new facet
336 facets.push_back(newFacet);
337 currentFacets.resize(currentFacets.size() + 1, true);
338 // increase Number Of new Facets
339 ++numberOfNewFacets;
340 }
341 }
342 }
343
344 for (auto visibleFacet : visibleSet) {
345 for (uint_fast64_t outsidePoint : facets[visibleFacet].outsideSet) {
346 currentOutsidePoints.set(outsidePoint, true);
347 }
348 currentFacets.set(visibleFacet, false);
349 }
350 // compute new outside sets
351 for (uint_fast64_t facetIndex : currentFacets) {
352 computeOutsideSetOfFacet(facets[facetIndex], currentOutsidePoints, points);
353 }
354
355 // find neighbors in new facets
356 setNeighborhoodOfNewFacets(facets, facets.size() - numberOfNewFacets, points.front().rows());
357 }
358 }
359}
360
361template<typename ValueType>
362void QuickHull<ValueType>::getPolytopeFromMesh(std::vector<EigenVector> const& points, std::vector<Facet> const& facets,
363 storm::storage::BitVector const& currentFacets, bool generateRelevantVerticesAndVertexSets) {
364 storm::storage::geometry::HyperplaneCollector<ValueType> hyperplaneCollector;
365 for (uint64_t facet : currentFacets) {
366 hyperplaneCollector.insert(std::move(facets[facet].normal), std::move(facets[facet].offset),
367 generateRelevantVerticesAndVertexSets ? &facets[facet].points : nullptr);
368 }
369
370 if (generateRelevantVerticesAndVertexSets) {
371 // Get the mapping from a hyperplane to the set of vertices that lie on that plane, erase the duplicates, and count for each vertex the number of
372 // hyperplanes on which that vertex lies
373 vertexSets = hyperplaneCollector.getIndexLists();
374 std::vector<uint_fast64_t> hyperplanesOnVertexCounter(points.size(), 0);
375 for (auto& vertexVector : vertexSets) {
376 std::set<uint_fast64_t> vertexSet;
377 for (auto const& i : vertexVector) {
378 if (vertexSet.insert(i).second) {
379 ++hyperplanesOnVertexCounter[i];
380 }
381 }
382 vertexVector.assign(vertexSet.begin(), vertexSet.end());
383 }
384 // Now, we can erase all vertices which do not lie on at least dimension hyperplanes.
385 // Note that the indices of the HyperplaneToVerticesMapping needs to be refreshed according to the new set of vertices
386 // Therefore, we additionally store the old indices for every vertex to be able to translate from old to new indices
387 std::unordered_map<EigenVector, std::vector<uint_fast64_t>> relevantVerticesMap;
388 relevantVerticesMap.reserve(points.size());
389 for (uint_fast64_t vertexIndex = 0; vertexIndex < hyperplanesOnVertexCounter.size(); ++vertexIndex) {
390 if ((Eigen::Index)hyperplanesOnVertexCounter[vertexIndex] >= points.front().rows()) {
391 auto mapEntry = relevantVerticesMap
392 .insert(typename std::unordered_map<EigenVector, std::vector<uint_fast64_t>>::value_type(points[vertexIndex],
393 std::vector<uint_fast64_t>()))
394 .first;
395 mapEntry->second.push_back(vertexIndex);
396 }
397 }
398 // Fill in the relevant vertices and create a translation map from old to new indices
399 std::vector<uint_fast64_t> oldToNewIndexMapping(points.size(), points.size()); // Initialize with some illegal value
400 relevantVertices.clear();
401 relevantVertices.reserve(relevantVerticesMap.size());
402 for (auto const& mapEntry : relevantVerticesMap) {
403 for (auto const& oldIndex : mapEntry.second) {
404 oldToNewIndexMapping[oldIndex] = relevantVertices.size();
405 }
406 relevantVertices.push_back(mapEntry.first);
407 }
408 // Actually translate and erase duplicates
409 for (auto& vertexVector : vertexSets) {
410 std::set<uint_fast64_t> vertexSet;
411 for (auto const& oldIndex : vertexVector) {
412 if ((Eigen::Index)hyperplanesOnVertexCounter[oldIndex] >= points.front().rows()) {
413 vertexSet.insert(oldToNewIndexMapping[oldIndex]);
414 }
415 }
416 vertexVector.assign(vertexSet.begin(), vertexSet.end());
417 }
418 } else {
419 relevantVertices.clear();
420 vertexSets.clear();
421 }
422 auto matrixVector = hyperplaneCollector.getCollectedHyperplanesAsMatrixVector();
423 resultMatrix = std::move(matrixVector.first);
424 resultVector = std::move(matrixVector.second);
425}
426
427template<typename ValueType>
428std::set<uint_fast64_t> QuickHull<ValueType>::getVisibleSet(std::vector<Facet> const& facets, uint_fast64_t const& startIndex, EigenVector const& point) const {
429 std::set<uint_fast64_t> facetsToCheck;
430 std::set<uint_fast64_t> facetsChecked;
431 std::set<uint_fast64_t> visibleSet;
432 facetsChecked.insert(startIndex);
433 visibleSet.insert(startIndex);
434 for (uint_fast64_t i = 0; i < facets[startIndex].neighbors.size(); ++i) {
435 facetsToCheck.insert(facets[startIndex].neighbors[i]);
436 }
437 while (!facetsToCheck.empty()) {
438 auto elementIt = facetsToCheck.begin();
439 if (point.dot(facets[*elementIt].normal) > facets[*elementIt].offset) {
440 visibleSet.insert(*elementIt);
441 for (uint_fast64_t i = 0; i < facets[*elementIt].neighbors.size(); ++i) {
442 if (facetsChecked.find(facets[*elementIt].neighbors[i]) == facetsChecked.end()) {
443 facetsToCheck.insert(facets[*elementIt].neighbors[i]);
444 }
445 }
446 }
447 facetsChecked.insert(*elementIt);
448 facetsToCheck.erase(elementIt);
449 }
450 return visibleSet;
451}
452
453template<typename ValueType>
454void QuickHull<ValueType>::setNeighborhoodOfNewFacets(std::vector<Facet>& facets, uint_fast64_t firstNewFacet, uint_fast64_t dimension) const {
455 for (uint_fast64_t currentFacet = firstNewFacet; currentFacet < facets.size(); ++currentFacet) {
456 for (uint_fast64_t otherFacet = currentFacet + 1; otherFacet < facets.size(); ++otherFacet) {
457 if (getCommonPoints(facets[currentFacet], facets[otherFacet]).size() >= dimension - 1) {
458 facets[currentFacet].neighbors.push_back(otherFacet);
459 facets[otherFacet].neighbors.push_back(currentFacet);
460 }
461 }
462 }
463}
464
465template<typename ValueType>
466void QuickHull<ValueType>::replaceFacetNeighbor(std::vector<Facet>& facets, uint_fast64_t oldFacetIndex, uint_fast64_t newFacetIndex,
467 uint_fast64_t neighborIndex) const {
468 auto facetInNeighborListIt = std::find(facets[neighborIndex].neighbors.begin(), facets[neighborIndex].neighbors.end(), oldFacetIndex);
469 if (facetInNeighborListIt != facets[neighborIndex].neighbors.end()) {
470 *facetInNeighborListIt = newFacetIndex;
471 }
472}
473
474template<typename ValueType>
475void QuickHull<ValueType>::computeOutsideSetOfFacet(Facet& facet, storm::storage::BitVector& currentOutsidePoints,
476 std::vector<EigenVector> const& points) const {
477 ValueType maxMultiplicationResult = facet.offset;
478 for (uint_fast64_t pointIndex : currentOutsidePoints) {
479 ValueType multiplicationResult = points[pointIndex].dot(facet.normal);
480 if (multiplicationResult > facet.offset) {
481 currentOutsidePoints.set(pointIndex, false); // we already know that the point lies outside so it can be ignored for future facets
482 facet.outsideSet.push_back(pointIndex);
483 if (multiplicationResult > maxMultiplicationResult) {
484 maxMultiplicationResult = multiplicationResult;
485 facet.maxOutsidePointIndex = pointIndex;
486 }
487 }
488 }
489}
490
491template<typename ValueType>
492std::vector<uint_fast64_t> QuickHull<ValueType>::getCommonPoints(Facet const& lhs, Facet const& rhs) const {
493 std::vector<uint_fast64_t> commonPoints;
494 for (uint_fast64_t lhsPoint : lhs.points) {
495 for (uint_fast64_t rhsPoint : rhs.points) {
496 if (lhsPoint == rhsPoint) {
497 commonPoints.push_back(lhsPoint);
498 }
499 }
500 }
501 return commonPoints;
502}
503
504template<typename ValueType>
505std::set<uint_fast64_t> QuickHull<ValueType>::getInvisibleNeighbors(std::vector<Facet>& facets, std::set<uint_fast64_t> const& visibleSet) const {
506 std::set<uint_fast64_t> invisibleNeighbors;
507 for (auto currentFacetIt = visibleSet.begin(); currentFacetIt != visibleSet.end(); ++currentFacetIt) {
508 for (uint_fast64_t currentNeighbor = 0; currentNeighbor < facets[*currentFacetIt].neighbors.size(); ++currentNeighbor) {
509 if (visibleSet.find(facets[*currentFacetIt].neighbors[currentNeighbor]) == visibleSet.end()) {
510 invisibleNeighbors.insert(facets[*currentFacetIt].neighbors[currentNeighbor]);
511 }
512 }
513 }
514 return invisibleNeighbors;
515}
516
517template class QuickHull<double>;
519
520} // namespace geometry
521} // namespace storage
522} // namespace storm
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
uint64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
bool insert(EigenVector const &normal, ValueType const &offset, std::vector< uint_fast64_t > const *indexList=nullptr)
std::vector< std::vector< uint_fast64_t > > getIndexLists() const
std::pair< EigenMatrix, EigenVector > getCollectedHyperplanesAsMatrixVector() const
Eigen::Matrix< ValueType, Eigen::Dynamic, Eigen::Dynamic > EigenMatrix
Definition QuickHull.h:15
std::vector< EigenVector > & getRelevantVertices()
Returns the set of vertices which are not redundant.
Definition QuickHull.cpp:65
Eigen::Matrix< ValueType, Eigen::Dynamic, 1 > EigenVector
Definition QuickHull.h:16
void generateHalfspacesFromPoints(std::vector< EigenVector > &points, bool generateRelevantVerticesAndVertexSets)
Definition QuickHull.cpp:19
std::vector< std::vector< std::uint_fast64_t > > & getVertexSets()
Returns for each hyperplane the set of vertices that lie on that hyperplane.
Definition QuickHull.cpp:70
#define STORM_LOG_WARN(message)
Definition logging.h:28
#define STORM_LOG_DEBUG(message)
Definition logging.h:21
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
SFTBDDChecker::ValueType ValueType
void filterVectorInPlace(std::vector< Type > &v, storm::storage::BitVector const &filter)
Definition vector.h:1071
ValueType one()
Definition constants.cpp:19
TargetType convertNumber(SourceType const &number)