18template<
typename ValueType>
20 if (halfspaces.empty()) {
24 Eigen::Index maxCol = halfspaces.front().normalVector().size();
25 Eigen::Index maxRow = halfspaces.size();
28 for (Eigen::Index row = 0; row < A.rows(); ++row) {
29 assert((Eigen::Index)halfspaces[row].normalVector().size() == maxCol);
30 b(row) = halfspaces[row].offset();
37template<
typename ValueType>
42 std::vector<EigenVector> eigenPoints;
43 eigenPoints.reserve(points.size());
44 for (
auto const& p : points) {
56template<
typename ValueType>
58 boost::optional<std::vector<Point>>
const& points) {
60 STORM_LOG_WARN_COND(!points,
"Creating a NativePolytope where halfspaces AND points are given. The points will be ignored.");
61 return std::make_shared<NativePolytope<ValueType>>(*halfspaces);
63 return std::make_shared<NativePolytope<ValueType>>(*points);
65 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException,
"Creating a NativePolytope but no representation was given.");
69template<
typename ValueType>
74template<
typename ValueType>
76 : emptyStatus(
std::move(other.emptyStatus)), A(
std::move(other.A)), b(
std::move(other.b)) {
80template<
typename ValueType>
82 : emptyStatus(emptyStatus), A(halfspaceMatrix), b(halfspaceVector) {
86template<
typename ValueType>
88 : emptyStatus(emptyStatus), A(halfspaceMatrix), b(halfspaceVector) {
92template<
typename ValueType>
97template<
typename ValueType>
99 std::vector<EigenVector> eigenVertices = getEigenVertices();
100 std::vector<Point> result;
101 result.reserve(eigenVertices.size());
102 for (
auto const& p : eigenVertices) {
108template<
typename ValueType>
110 std::vector<Halfspace<ValueType>> result;
111 result.reserve(A.rows());
113 for (Eigen::Index row = 0; row < A.rows(); ++row) {
119template<
typename ValueType>
125 for (
auto const& constraint : constraints) {
128 switch (
solver->check()) {
136 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException,
"Unexpected result of SMT solver during emptyness-check of Polytope.");
143template<
typename ValueType>
145 return A.rows() == 0;
148template<
typename ValueType>
151 for (Eigen::Index row = 0; row < A.rows(); ++row) {
152 if ((A.row(row) * x)(0) > b(row)) {
159template<
typename ValueType>
161 STORM_LOG_THROW(other->isNativePolytope(), storm::exceptions::InvalidArgumentException,
162 "Invoked operation between a NativePolytope and a different polytope implementation. This is not supported");
165 }
else if (other->isUniversal()) {
171 std::vector<storm::expressions::Variable> variables =
declareVariables(*manager,
"x");
172 std::vector<storm::expressions::Expression> constraints =
getConstraints(*manager, variables);
174 for (
auto const& constraint : constraints) {
175 constraintsThis = constraintsThis && constraint;
177 solver->add(!constraintsThis);
179 for (
auto const& constraint : constraints) {
182 switch (
solver->check()) {
188 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException,
"Unexpected result of SMT solver during containment check of two polytopes.");
194template<
typename ValueType>
196 STORM_LOG_THROW(rhs->isNativePolytope(), storm::exceptions::InvalidArgumentException,
197 "Invoked operation between a NativePolytope and a different polytope implementation. This is not supported");
200 }
else if (rhs->isUniversal()) {
201 return std::make_shared<NativePolytope<ValueType>>(*this);
204 EigenMatrix resultA(A.rows() + nativeRhs.A.rows(), A.cols());
205 resultA << A, nativeRhs.A;
207 resultb << b, nativeRhs.b;
208 return std::make_shared<NativePolytope<ValueType>>(
EmptyStatus::Unknown, std::move(resultA), std::move(resultb));
212template<
typename ValueType>
218 resultb(0) = halfspace.
offset();
219 return std::make_shared<NativePolytope<ValueType>>(
EmptyStatus::Unknown, std::move(resultA), std::move(resultb));
224 resultb << b, halfspace.
offset();
225 return std::make_shared<NativePolytope<ValueType>>(
EmptyStatus::Unknown, std::move(resultA), std::move(resultb));
228template<
typename ValueType>
230 STORM_LOG_THROW(rhs->isNativePolytope(), storm::exceptions::InvalidArgumentException,
231 "Invoked operation between a NativePolytope and a different polytope implementation. This is not supported");
234 }
else if (rhs->isEmpty()) {
235 return std::make_shared<NativePolytope<ValueType>>(*this);
236 }
else if (this->
isUniversal() || rhs->isUniversal()) {
237 return std::make_shared<NativePolytope<ValueType>>(std::vector<Halfspace<ValueType>>());
240 STORM_LOG_WARN_COND_DEBUG(
false,
"Implementation of convex union of two polytopes only works if the polytopes are bounded. This is not checked.");
243 std::vector<EigenVector> resultVertices = this->getEigenVertices();
244 resultVertices.insert(resultVertices.end(), std::make_move_iterator(rhsVertices.begin()), std::make_move_iterator(rhsVertices.end()));
251template<
typename ValueType>
253 STORM_LOG_THROW(rhs->isNativePolytope(), storm::exceptions::InvalidArgumentException,
254 "Invoked operation between a NativePolytope and a different polytope implementation. This is not supported");
258 return std::make_shared<NativePolytope<ValueType>>(std::vector<Point>());
261 std::vector<std::pair<EigenVector, ValueType>> resultConstraints;
262 resultConstraints.reserve(A.rows() + nativeRhs.A.rows());
265 for (Eigen::Index
i = 0;
i < A.rows(); ++
i) {
266 auto optimizationRes = nativeRhs.
optimize(A.row(
i));
267 if (optimizationRes.second) {
268 resultConstraints.emplace_back(A.row(
i), b(
i) + (A.row(
i) * optimizationRes.first)(0));
274 for (Eigen::Index
i = 0;
i < nativeRhs.A.rows(); ++
i) {
275 auto optimizationRes =
optimize(nativeRhs.A.row(
i));
276 if (optimizationRes.second) {
277 resultConstraints.emplace_back(nativeRhs.A.row(
i), nativeRhs.b(
i) + (nativeRhs.A.row(
i) * optimizationRes.first)(0));
282 if (resultConstraints.empty()) {
283 return std::make_shared<NativePolytope<ValueType>>(std::vector<Halfspace<ValueType>>());
285 EigenMatrix newA(resultConstraints.size(), resultConstraints.front().first.rows());
287 for (Eigen::Index
i = 0;
i < newA.rows(); ++
i) {
288 newA.row(
i) = resultConstraints[
i].first;
289 newb(
i) = resultConstraints[
i].second;
291 return std::make_shared<NativePolytope<ValueType>>(
EmptyStatus::Nonempty, std::move(newA), std::move(newb));
295template<
typename ValueType>
297 STORM_LOG_THROW(!matrix.empty(), storm::exceptions::InvalidArgumentException,
"Invoked affine transformation with a matrix without rows.");
298 Eigen::Index rows = matrix.size();
299 Eigen::Index columns = matrix.front().size();
301 for (Eigen::Index row = 0; row < rows; ++row) {
306 Eigen::FullPivLU<EigenMatrix> luMatrix(eigenMatrix);
307 STORM_LOG_THROW(luMatrix.isInvertible(), storm::exceptions::NotImplementedException,
308 "Affine Transformation of native polytope only implemented if the transformation matrix is invertable");
310 return std::make_shared<NativePolytope<ValueType>>(std::vector<Halfspace<ValueType>>());
314 return std::make_shared<NativePolytope<ValueType>>(emptyStatus, std::move(newA), std::move(newb));
317template<
typename ValueType>
320 return std::make_pair(
Point(),
false);
324 std::vector<storm::expressions::Variable> variables;
325 variables.reserve(A.cols());
326 for (Eigen::Index
i = 0;
i < A.cols(); ++
i) {
327 variables.push_back(
solver.addUnboundedContinuousVariable(
"x" + std::to_string(
i), direction[
i]));
329 std::vector<storm::expressions::Expression> constraints =
getConstraints(
solver.getManager(), variables);
330 for (
auto const& constraint : constraints) {
331 solver.addConstraint(
"", constraint);
336 auto result = std::make_pair(
Point(),
true);
337 result.first.reserve(variables.size());
338 for (
auto const& var : variables) {
339 result.first.push_back(
solver.getContinuousValue(var));
344 return std::make_pair(
Point(),
false);
348template<
typename ValueType>
351 return std::make_pair(EigenVector(),
false);
355 std::vector<storm::expressions::Variable> variables;
356 variables.reserve(A.cols());
357 for (Eigen::Index
i = 0;
i < A.cols(); ++
i) {
358 variables.push_back(
solver.addUnboundedContinuousVariable(
"x" + std::to_string(
i),
static_cast<ValueType
>(direction(
i))));
360 std::vector<storm::expressions::Expression> constraints = getConstraints(
solver.getManager(), variables);
361 for (
auto const& constraint : constraints) {
362 solver.addConstraint(
"", constraint);
366 if (solver.isOptimal()) {
367 auto result = std::make_pair(EigenVector(A.cols()),
true);
368 for (Eigen::Index
i = 0;
i < A.cols(); ++
i) {
369 result.first(
i) = solver.getContinuousValue(variables[
i]);
374 return std::make_pair(EigenVector(),
false);
378template<
typename ValueType>
382template<
typename ValueType>
383std::vector<typename NativePolytope<ValueType>::EigenVector> NativePolytope<ValueType>::getEigenVertices()
const {
389template<
typename ValueType>
391 std::string
const& namePrefix)
const {
392 std::vector<storm::expressions::Variable> result;
393 result.reserve(A.cols());
394 for (Eigen::Index col = 0; col < A.cols(); ++col) {
395 result.push_back(manager.declareVariable(namePrefix + std::to_string(col), manager.getRationalType()));
400template<
typename ValueType>
402 std::vector<storm::expressions::Variable>
const& variables)
const {
403 std::vector<storm::expressions::Expression> result;
404 for (Eigen::Index row = 0; row < A.rows(); ++row) {
406 for (Eigen::Index col = 1; col < A.cols(); ++col) {
407 lhs = lhs + manager.rational(A(row, col)) * variables[col].getExpression();
409 result.push_back(lhs <= manager.rational(b(row)));
414template<
typename ValueType>
417 return create(boost::none, {});
422 std::vector<storm::expressions::Expression> constraints =
getConstraints(*manager, variables);
423 for (
auto const& constraint : constraints) {
427 for (Eigen::Index row = 0; row < A.rows(); ++row) {
429 for (Eigen::Index col = 1; col < A.cols(); ++col) {
430 lhs = lhs + manager->rational(A(row, col)) * variables[col].getExpression();
433 solver->add(lhs >= manager->rational(b(row)));
434 switch (
solver->check()) {
436 keptConstraints.
set(row,
true);
440 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException,
"Unexpected result of SMT solver during emptyness-check of Polytope.");
445 std::vector<Halfspace<ValueType>> newHalfspaces;
447 for (
auto row : keptConstraints) {
450 return create(newHalfspaces, boost::none);
static Eigen::Matrix< ValueType, Eigen::Dynamic, 1 > toEigenVector(std::vector< ValueType > const &v)
static std::vector< ValueType > toStdVector(Eigen::Matrix< ValueType, Eigen::Dynamic, 1 > const &v)
This class is responsible for managing a set of typed variables and all expressions using these varia...
A class that implements the LpSolver interface using Z3.
A bit vector that is internally represented as a vector of 64-bit values.
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.
std::vector< ValueType > const & normalVector() const
ValueType const & offset() const
std::vector< EigenVector > & getResultVertices()
void generateVerticesFromConstraints(EigenMatrix const &constraintMatrix, EigenVector const &constraintVector, bool generateRelevantHyperplanesAndVertexSets)
virtual bool contains(Point const &point) const override
Returns true iff the given point is inside of the polytope.
NativePolytope(std::vector< Halfspace< ValueType > > const &halfspaces)
Creates a NativePolytope from the given halfspaces The resulting polytope is defined as the intersect...
Eigen::Matrix< ValueType, Eigen::Dynamic, Eigen::Dynamic > EigenMatrix
virtual std::vector< storm::expressions::Variable > declareVariables(storm::expressions::ExpressionManager &manager, std::string const &namePrefix) const override
declares one variable for each dimension and returns the obtained variables.
virtual std::pair< Point, bool > optimize(Point const &direction) const override
Finds an optimal point inside this polytope w.r.t.
virtual std::shared_ptr< Polytope< ValueType > > clean() override
Performs cleaning operations, e.g., deleting redundant halfspaces.
virtual std::shared_ptr< Polytope< ValueType > > affineTransformation(std::vector< Point > const &matrix, Point const &vector) const override
Returns the affine transformation of this polytope P w.r.t.
virtual bool isNativePolytope() const override
Polytope< ValueType >::Point Point
virtual std::vector< Point > getVertices() const override
Returns the vertices of this polytope.
Eigen::Matrix< ValueType, Eigen::Dynamic, 1 > EigenVector
virtual bool isUniversal() const override
Returns whether this polytope is universal (i.e., equals R^n).
virtual std::shared_ptr< Polytope< ValueType > > intersection(std::shared_ptr< Polytope< ValueType > > const &rhs) const override
Intersects this polytope with rhs and returns the result.
virtual std::shared_ptr< Polytope< ValueType > > minkowskiSum(std::shared_ptr< Polytope< ValueType > > const &rhs) const override
Returns the minkowskiSum of this polytope and rhs.
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.
virtual bool isEmpty() const override
Returns whether this polytope is the empty set.
virtual std::vector< storm::expressions::Expression > getConstraints(storm::expressions::ExpressionManager const &manager, std::vector< storm::expressions::Variable > const &variables) const override
returns the constrains defined by this polytope as an expression over the given variables
virtual ~NativePolytope()
virtual std::vector< Halfspace< ValueType > > getHalfspaces() const override
Returns the halfspaces of this polytope.
virtual std::shared_ptr< Polytope< ValueType > > convexUnion(std::shared_ptr< Polytope< ValueType > > const &rhs) const override
Returns the convex union of this polytope and rhs.
void generateHalfspacesFromPoints(std::vector< EigenVector > &points, bool generateRelevantVerticesAndVertexSets)
EigenMatrix & getResultMatrix()
EigenVector & getResultVector()
virtual std::unique_ptr< storm::solver::SmtSolver > create(storm::expressions::ExpressionManager &manager) const
Creates a new SMT solver instance.
#define STORM_LOG_WARN_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
#define STORM_LOG_WARN_COND_DEBUG(cond, message)