blob: 1ca1ec68777860edb06b051cf66172967e313e70 [file] [log] [blame]
#ifndef AOS_COMMON_CONTROLS_POLYTOPE_H_
#define AOS_COMMON_CONTROLS_POLYTOPE_H_
#include "Eigen/Dense"
#ifdef AOS_BAZEL
#include "third_party/cddlib/lib-src/setoper.h"
#include "third_party/cddlib/lib-src/cdd.h"
#else
#include "libcdd-094g-prefix/include/setoper.h"
#include "libcdd-094g-prefix/include/cdd.h"
#endif
namespace aos {
namespace controls {
// A n dimension polytope.
template <int number_of_dimensions>
class HPolytope {
public:
// Constructs a polytope given the H and k matricies.
HPolytope(Eigen::Matrix<double, Eigen::Dynamic, number_of_dimensions> H,
Eigen::Matrix<double, Eigen::Dynamic, 1> k)
: H_(H),
k_(k) {
}
// This is an initialization function shared across all instantiations of this
// template.
// This must be called at least once before calling any of the methods. It is
// not thread-safe.
static void Init() {
dd_set_global_constants();
}
// Returns a reference to H.
const Eigen::Matrix<double, Eigen::Dynamic,
number_of_dimensions> &H() const {
return H_;
}
// Returns a reference to k.
const Eigen::Matrix<double, Eigen::Dynamic,
1> &k() const {
return k_;
}
// Returns the number of dimensions in the polytope.
int ndim() const { return number_of_dimensions; }
// Returns the number of constraints currently in the polytope.
int num_constraints() const { return k_.rows(); }
// Returns true if the point is inside the polytope.
bool IsInside(Eigen::Matrix<double, number_of_dimensions, 1> point) const;
// Returns the list of vertices inside the polytope.
Eigen::Matrix<double, number_of_dimensions, Eigen::Dynamic> Vertices() const;
private:
Eigen::Matrix<double, Eigen::Dynamic, number_of_dimensions> H_;
Eigen::Matrix<double, Eigen::Dynamic, 1> k_;
};
template <int number_of_dimensions>
bool HPolytope<number_of_dimensions>::IsInside(
Eigen::Matrix<double, number_of_dimensions, 1> point) const {
auto ev = H_ * point;
for (int i = 0; i < num_constraints(); ++i) {
if (ev(i, 0) > k_(i, 0)) {
return false;
}
}
return true;
}
template <int number_of_dimensions>
Eigen::Matrix<double, number_of_dimensions, Eigen::Dynamic>
HPolytope<number_of_dimensions>::Vertices() const {
dd_MatrixPtr matrix = dd_CreateMatrix(num_constraints(), ndim() + 1);
// Copy the data over. TODO(aschuh): Is there a better way? I hate copying...
for (int i = 0; i < num_constraints(); ++i) {
dd_set_d(matrix->matrix[i][0], k_(i, 0));
for (int j = 0; j < ndim(); ++j) {
dd_set_d(matrix->matrix[i][j + 1], -H_(i, j));
}
}
matrix->representation = dd_Inequality;
matrix->numbtype = dd_Real;
dd_ErrorType error;
dd_PolyhedraPtr polyhedra = dd_DDMatrix2Poly(matrix, &error);
if (error != dd_NoError || polyhedra == NULL) {
dd_WriteErrorMessages(stderr, error);
dd_FreeMatrix(matrix);
Eigen::Matrix<double, number_of_dimensions, Eigen::Dynamic> ans(0, 0);
return ans;
}
dd_MatrixPtr vertex_matrix = dd_CopyGenerators(polyhedra);
int num_vertices = 0;
int num_rays = 0;
for (int i = 0; i < vertex_matrix->rowsize; ++i) {
if (dd_get_d(vertex_matrix->matrix[i][0]) == 0) {
num_rays += 1;
} else {
num_vertices += 1;
}
}
Eigen::Matrix<double, number_of_dimensions, Eigen::Dynamic> vertices(
number_of_dimensions, num_vertices);
int vertex_index = 0;
for (int i = 0; i < vertex_matrix->rowsize; ++i) {
if (dd_get_d(vertex_matrix->matrix[i][0]) != 0) {
for (int j = 0; j < number_of_dimensions; ++j) {
vertices(j, vertex_index) = dd_get_d(vertex_matrix->matrix[i][j + 1]);
}
++vertex_index;
}
}
dd_FreeMatrix(vertex_matrix);
dd_FreePolyhedra(polyhedra);
dd_FreeMatrix(matrix);
return vertices;
}
} // namespace controls
} // namespace aos
#endif // AOS_COMMON_CONTROLS_POLYTOPE_H_