Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
HyperplaneEnumeration.cpp
Go to the documentation of this file.
2
6
7namespace storm {
8namespace storage {
9namespace geometry {
10
11template<typename ValueType>
13 bool generateRelevantHyperplanesAndVertexSets) {
14 STORM_LOG_DEBUG("Invoked Hyperplane enumeration with " << constraintMatrix.rows() << " constraints.");
15 Eigen::Index dimension = constraintMatrix.cols();
16 if (dimension == 0) {
17 // No halfspaces means no vertices
18 resultVertices.clear();
19 relevantMatrix = constraintMatrix;
20 relevantVector = constraintVector;
21 vertexSets.clear();
22 return;
23 }
24 std::unordered_map<EigenVector, std::set<uint_fast64_t>> vertexCollector;
25 storm::storage::geometry::SubsetEnumerator<EigenMatrix> subsetEnum(constraintMatrix.rows(), dimension, constraintMatrix, this->linearDependenciesFilter);
26 if (subsetEnum.setToFirstSubset()) {
27 do {
28 std::vector<uint_fast64_t> const& subset = subsetEnum.getCurrentSubset();
29
30 EigenMatrix subMatrix(dimension, dimension);
31 EigenVector subVector(dimension);
32 for (Eigen::Index i = 0; i < dimension; ++i) {
33 subMatrix.row(i) = constraintMatrix.row(subset[i]);
34 subVector(i) = constraintVector(subset[i]);
35 }
36
37 EigenVector point = subMatrix.fullPivLu().solve(subVector);
38 bool pointContained = true;
39 for (Eigen::Index row = 0; row < constraintMatrix.rows(); ++row) {
40 if ((constraintMatrix.row(row) * point)(0) > constraintVector(row)) {
41 pointContained = false;
42 break;
43 }
44 }
45 if (pointContained) {
46 // Note that the map avoids duplicates.
47 auto hyperplaneIndices =
48 vertexCollector
49 .insert(typename std::unordered_map<EigenVector, std::set<uint_fast64_t>>::value_type(std::move(point), std::set<uint_fast64_t>()))
50 .first;
51 if (generateRelevantHyperplanesAndVertexSets) {
52 hyperplaneIndices->second.insert(subset.begin(), subset.end());
53 }
54 }
55 } while (subsetEnum.incrementSubset());
56 }
57
58 if (generateRelevantHyperplanesAndVertexSets) {
59 // For each hyperplane, get the number of (unique) vertices that lie on it.
60 std::vector<Eigen::Index> verticesOnHyperplaneCounter(constraintMatrix.rows(), 0);
61 for (auto const& mapEntry : vertexCollector) {
62 for (auto const& hyperplaneIndex : mapEntry.second) {
63 ++verticesOnHyperplaneCounter[hyperplaneIndex];
64 }
65 }
66
67 // Only keep the hyperplanes on which at least dimension() vertices lie.
68 // Note that this will change the indices of the Hyperplanes.
69 // Therefore, we additionally store the old indices for every hyperplane to be able to translate from old to new indices
71 for (uint_fast64_t hyperplaneIndex = 0; hyperplaneIndex < verticesOnHyperplaneCounter.size(); ++hyperplaneIndex) {
72 if (verticesOnHyperplaneCounter[hyperplaneIndex] >= dimension) {
73 std::vector<uint_fast64_t> oldIndex;
74 oldIndex.push_back(hyperplaneIndex);
75 hyperplaneCollector.insert(constraintMatrix.row(hyperplaneIndex), constraintVector(hyperplaneIndex), &oldIndex);
76 }
77 }
78 auto matrixVector = hyperplaneCollector.getCollectedHyperplanesAsMatrixVector();
79 relevantMatrix = std::move(matrixVector.first);
80 relevantVector = std::move(matrixVector.second);
81
82 // Get the mapping from old to new indices
83 std::vector<uint_fast64_t> oldToNewIndexMapping(constraintMatrix.rows(), constraintMatrix.rows()); // Initialize with some illegal value
84 std::vector<std::vector<uint_fast64_t>> newToOldIndexMapping(hyperplaneCollector.getIndexLists());
85 for (uint_fast64_t newIndex = 0; newIndex < newToOldIndexMapping.size(); ++newIndex) {
86 for (auto const& oldIndex : newToOldIndexMapping[newIndex]) {
87 oldToNewIndexMapping[oldIndex] = newIndex;
88 }
89 }
90
91 // Insert the resulting vertices and get the set of vertices that lie on each hyperplane
92 std::vector<std::set<uint_fast64_t>> vertexSets(relevantMatrix.rows());
93 resultVertices.clear();
94 resultVertices.reserve(vertexCollector.size());
95 for (auto const& mapEntry : vertexCollector) {
96 for (auto const& oldHyperplaneIndex : mapEntry.second) {
97 // ignore the hyperplanes which are redundant, i.e. for which there is no new index
98 if ((Eigen::Index)oldToNewIndexMapping[oldHyperplaneIndex] < relevantVector.rows()) {
99 vertexSets[oldToNewIndexMapping[oldHyperplaneIndex]].insert(resultVertices.size());
100 }
101 }
102 resultVertices.push_back(mapEntry.first);
103 }
104 this->vertexSets.clear();
105 this->vertexSets.reserve(vertexSets.size());
106 for (auto const& vertexSet : vertexSets) {
107 this->vertexSets.emplace_back(vertexSet.begin(), vertexSet.end());
108 }
109
110 } else {
111 resultVertices.clear();
112 resultVertices.reserve(vertexCollector.size());
113 for (auto const& mapEntry : vertexCollector) {
114 resultVertices.push_back(mapEntry.first);
115 }
116 this->vertexSets.clear();
117 relevantMatrix = EigenMatrix();
118 relevantVector = EigenVector();
119 }
120}
121
122template<typename ValueType>
123bool HyperplaneEnumeration<ValueType>::linearDependenciesFilter(std::vector<uint_fast64_t> const& subset, uint_fast64_t const& item, EigenMatrix const& A) {
124 EigenMatrix subMatrix(subset.size() + 1, A.cols());
125 for (uint_fast64_t i = 0; i < subset.size(); ++i) {
126 subMatrix.row((Eigen::Index)i) = A.row(Eigen::Index(subset[i]));
127 }
128 subMatrix.row(subset.size()) = A.row(item);
129 Eigen::FullPivLU<EigenMatrix> lUMatrix(subMatrix);
130 if (lUMatrix.rank() < subMatrix.rows()) {
131 // Linear dependent!
132 return false;
133 } else {
134 return true;
135 }
136}
137
138template<typename ValueType>
139std::vector<typename HyperplaneEnumeration<ValueType>::EigenVector>& HyperplaneEnumeration<ValueType>::getResultVertices() {
140 return resultVertices;
141}
142
143template<typename ValueType>
147
148template<typename ValueType>
152
153template<typename ValueType>
154std::vector<std::vector<uint_fast64_t>>& HyperplaneEnumeration<ValueType>::getVertexSets() {
155 return this->vertexSets;
156}
157
158template class HyperplaneEnumeration<double>;
160
161} // namespace geometry
162} // namespace storage
163} // namespace storm
This class can be used to collect a set of hyperplanes (without duplicates).
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
static bool linearDependenciesFilter(std::vector< uint_fast64_t > const &subset, uint_fast64_t const &item, EigenMatrix const &A)
void generateVerticesFromConstraints(EigenMatrix const &constraintMatrix, EigenVector const &constraintVector, bool generateRelevantHyperplanesAndVertexSets)
EigenMatrix & getRelevantMatrix()
Returns the set of halfspaces which are not redundant.
std::vector< std::vector< uint_fast64_t > > & getVertexSets()
Returns for each hyperplane the set of vertices that lie on that hyperplane.
Eigen::Matrix< ValueType, Eigen::Dynamic, Eigen::Dynamic > EigenMatrix
Eigen::Matrix< ValueType, Eigen::Dynamic, 1 > EigenVector
This class can be used to enumerate all k-sized subsets of {0,...,n-1}.
std::vector< uint_fast64_t > const & getCurrentSubset()
#define STORM_LOG_DEBUG(message)
Definition logging.h:23
LabParser.cpp.
Definition cli.cpp:18