-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for sparse Eigen matrices in Hpolytope class #327
Changes from 9 commits
933fe04
29ca44e
83a38be
2dea296
2ad4bfa
4498490
bf93e1f
08c0f66
fe8f92c
0394b98
6fe2cf5
52c731e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,3 +9,4 @@ test/Testing/Temporary/CTestCostData.txt | |
build/ | ||
.vscode | ||
.DS_Store | ||
.cache |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,23 +41,29 @@ bool is_inner_point_nan_inf(VT const& p) | |
/// This class describes a polytope in H-representation or an H-polytope | ||
/// i.e. a polytope defined by a set of linear inequalities | ||
/// \tparam Point Point type | ||
template <typename Point> | ||
template | ||
< | ||
typename Point, | ||
typename MT_type = Eigen::Matrix<typename Point::FT, Eigen::Dynamic, Eigen::Dynamic> | ||
> | ||
class HPolytope { | ||
public: | ||
typedef Point PointType; | ||
typedef typename Point::FT NT; | ||
typedef typename std::vector<NT>::iterator viterator; | ||
//using RowMatrixXd = Eigen::Matrix<NT, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>; | ||
//typedef RowMatrixXd MT; | ||
typedef Eigen::Matrix<NT, Eigen::Dynamic, Eigen::Dynamic> MT; | ||
typedef MT_type MT; | ||
typedef Eigen::Matrix<NT, Eigen::Dynamic, 1> VT; | ||
typedef Eigen::Matrix<NT, Eigen::Dynamic, Eigen::Dynamic> DenseMT; | ||
|
||
private: | ||
unsigned int _d; //dimension | ||
MT A; //matrix A | ||
VT b; // vector b, s.t.: Ax<=b | ||
std::pair<Point, NT> _inner_ball; | ||
bool normalized = false; // true if the polytope is normalized | ||
bool has_ball = false; | ||
|
||
public: | ||
//TODO: the default implementation of the Big3 should be ok. Recheck. | ||
|
@@ -68,9 +74,15 @@ class HPolytope { | |
{ | ||
} | ||
|
||
template<typename T = DenseMT> | ||
HPolytope(unsigned d_, DenseMT const& A_, VT const& b_, typename std::enable_if<!std::is_same<MT, T>::value, T>::type* = 0) : | ||
_d{d_}, A{A_.sparseView()}, b{b_} | ||
{ | ||
} | ||
|
||
// Copy constructor | ||
HPolytope(HPolytope<Point> const& p) : | ||
_d{p._d}, A{p.A}, b{p.b}, _inner_ball{p._inner_ball}, normalized{p.normalized} | ||
HPolytope(HPolytope<Point, MT> const& p) : | ||
_d{p._d}, A{p.A}, b{p.b}, _inner_ball{p._inner_ball}, normalized{p.normalized}, has_ball{p.has_ball} | ||
{ | ||
} | ||
|
||
|
@@ -84,10 +96,10 @@ class HPolytope { | |
for (unsigned int i = 1; i < Pin.size(); i++) { | ||
b(i - 1) = Pin[i][0]; | ||
for (unsigned int j = 1; j < _d + 1; j++) { | ||
A(i - 1, j - 1) = -Pin[i][j]; | ||
A.coeffRef(i - 1, j - 1) = -Pin[i][j]; | ||
} | ||
} | ||
_inner_ball.second = -1; | ||
has_ball = false; | ||
//_inner_ball = ComputeChebychevBall<NT, Point>(A, b); | ||
} | ||
|
||
|
@@ -100,6 +112,7 @@ class HPolytope { | |
void set_InnerBall(std::pair<Point,NT> const& innerball) //const | ||
{ | ||
_inner_ball = innerball; | ||
has_ball = true; | ||
} | ||
|
||
void set_interior_point(Point const& r) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a TODO here to fix this function? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I decided to set the has_ball to true here since I assumed that whenever this function might be used, it would be given a valid innerball, but tbh I haven't seen anywhere in the code where this function is called anyways. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fisrt, we need to check that the point is indeed inside the polytope and only then set it as center of the inner ball. Then, we need to compute the distances of the center from all the facets and take the minimum. The latter distance is the radius of the maximum inscribed ball centered at the given point. The distance between a point p and the i-th facet is given by: (b_i - a_i^Tp) / ||a_i||. |
||
|
@@ -112,29 +125,29 @@ class HPolytope { | |
std::pair<Point, NT> ComputeInnerBall() | ||
{ | ||
normalize(); | ||
#ifndef DISABLE_LPSOLVE | ||
_inner_ball = ComputeChebychevBall<NT, Point>(A, b); // use lpsolve library | ||
#else | ||
|
||
if (_inner_ball.second <= NT(0)) { | ||
|
||
NT const tol = 1e-08; | ||
std::tuple<VT, NT, bool> inner_ball = max_inscribed_ball(A, b, 5000, tol); | ||
|
||
// check if the solution is feasible | ||
if (is_in(Point(std::get<0>(inner_ball))) == 0 || std::get<1>(inner_ball) < tol/2.0 || | ||
std::isnan(std::get<1>(inner_ball)) || std::isinf(std::get<1>(inner_ball)) || | ||
is_inner_point_nan_inf(std::get<0>(inner_ball))) | ||
{ | ||
_inner_ball.second = -1.0; | ||
} else | ||
{ | ||
_inner_ball.first = Point(std::get<0>(inner_ball)); | ||
_inner_ball.second = std::get<1>(inner_ball); | ||
} | ||
if (!has_ball) { | ||
|
||
has_ball = true; | ||
NT const tol = 1e-08; | ||
std::tuple<VT, NT, bool> inner_ball = max_inscribed_ball(A, b, 5000, tol); | ||
|
||
// check if the solution is feasible | ||
if (is_in(Point(std::get<0>(inner_ball))) == 0 || std::get<1>(inner_ball) < tol/2.0 || | ||
std::isnan(std::get<1>(inner_ball)) || std::isinf(std::get<1>(inner_ball)) || | ||
is_inner_point_nan_inf(std::get<0>(inner_ball))) { | ||
|
||
std::cerr << "Failed to compute max inscribed ball, trying to use lpsolve" << std::endl; | ||
#ifndef DISABLE_LPSOLVE | ||
_inner_ball = ComputeChebychevBall<NT, Point>(A, b); // use lpsolve library | ||
#else | ||
std::cerr << "lpsolve is disabled, unable to compute inner ball"; | ||
has_ball = false; | ||
#endif | ||
} else { | ||
_inner_ball.first = Point(std::get<0>(inner_ball)); | ||
_inner_ball.second = std::get<1>(inner_ball); | ||
} | ||
#endif | ||
|
||
} | ||
return _inner_ball; | ||
} | ||
|
||
|
@@ -185,13 +198,15 @@ class HPolytope { | |
{ | ||
A = A2; | ||
normalized = false; | ||
has_ball = false; | ||
} | ||
|
||
|
||
// change the vector b | ||
void set_vec(VT const& b2) | ||
{ | ||
b = b2; | ||
has_ball = false; | ||
} | ||
|
||
Point get_mean_of_vertices() const | ||
|
@@ -210,7 +225,7 @@ class HPolytope { | |
std::cout << " " << A.rows() << " " << _d << " double" << std::endl; | ||
for (unsigned int i = 0; i < A.rows(); i++) { | ||
for (unsigned int j = 0; j < _d; j++) { | ||
std::cout << A(i, j) << " "; | ||
std::cout << A.coeff(i, j) << " "; | ||
} | ||
std::cout << "<= " << b(i) << std::endl; | ||
} | ||
|
@@ -509,7 +524,7 @@ class HPolytope { | |
if(params.hit_ball) { | ||
Av.noalias() += (-2.0 * inner_prev) * (Ar / params.ball_inner_norm); | ||
} else { | ||
Av.noalias() += (-2.0 * inner_prev) * AA.col(params.facet_prev); | ||
Av.noalias() += (DenseMT)((-2.0 * inner_prev) * AA.col(params.facet_prev)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Input matrix AA should always be dense. Then, (DenseMT) is not needed here. |
||
} | ||
sum_nom.noalias() = b - Ar; | ||
|
||
|
@@ -630,12 +645,12 @@ class HPolytope { | |
|
||
int m = num_of_hyperplanes(); | ||
|
||
lamdas.noalias() += A.col(rand_coord_prev) | ||
* (r_prev[rand_coord_prev] - r[rand_coord_prev]); | ||
lamdas.noalias() += (DenseMT)(A.col(rand_coord_prev) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would |
||
* (r_prev[rand_coord_prev] - r[rand_coord_prev])); | ||
NT* data = lamdas.data(); | ||
|
||
for (int i = 0; i < m; i++) { | ||
NT a = A(i, rand_coord); | ||
NT a = A.coeff(i, rand_coord); | ||
|
||
if (a == NT(0)) { | ||
//std::cout<<"div0"<<std::endl; | ||
|
@@ -826,10 +841,16 @@ class HPolytope { | |
|
||
|
||
// Apply linear transformation, of square matrix T^{-1}, in H-polytope P:= Ax<=b | ||
void linear_transformIt(MT const& T) | ||
template<typename T_type> | ||
void linear_transformIt(T_type const& T) | ||
{ | ||
A = A * T; | ||
if constexpr (std::is_same<MT, DenseMT>::value) { | ||
A = A * T; | ||
} else { | ||
A = (A * T).sparseView(); | ||
} | ||
normalized = false; | ||
has_ball = false; | ||
} | ||
|
||
|
||
|
@@ -838,6 +859,7 @@ class HPolytope { | |
void shift(const VT &c) | ||
{ | ||
b -= A*c; | ||
has_ball = false; | ||
} | ||
|
||
|
||
|
@@ -867,12 +889,15 @@ class HPolytope { | |
|
||
void normalize() | ||
{ | ||
if(normalized) | ||
return; | ||
NT row_norm; | ||
for (int i = 0; i < num_of_hyperplanes(); ++i) | ||
{ | ||
for (int i = 0; i < A.rows(); ++i) { | ||
row_norm = A.row(i).norm(); | ||
A.row(i) = A.row(i) / row_norm; | ||
b(i) = b(i) / row_norm; | ||
if (row_norm != 0.0) { | ||
A.row(i) /= row_norm; | ||
b(i) /= row_norm; | ||
} | ||
} | ||
normalized = true; | ||
} | ||
|
@@ -919,7 +944,7 @@ class HPolytope { | |
} | ||
|
||
template <typename update_parameters> | ||
NT compute_reflection(Point &v, const Point &, MT const &AE, VT const &AEA, NT const &vEv, update_parameters const ¶ms) const { | ||
NT compute_reflection(Point &v, const Point &, DenseMT const &AE, VT const &AEA, NT const &vEv, update_parameters const ¶ms) const { | ||
|
||
Point a((-2.0 * params.inner_vi_ak) * A.row(params.facet_prev)); | ||
VT x = v.getCoefficients(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need those two lines?