-
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
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
933fe04
indentation and start of sparse support
lucaperju 29ca44e
sparse matrix support for hpolytope and gabw
lucaperju 83a38be
unit tests and minor fixes
lucaperju 2dea296
fix conflict bug
lucaperju 2ad4bfa
remove debug print and change variable names
lucaperju 4498490
fix innerBall bug
lucaperju bf93e1f
has_ball flag, separate A_type and E_type in GABW, improve unit test
lucaperju 08c0f66
rounding and volume_cg unit tests for sparse hpoly
lucaperju fe8f92c
sampling test for sparse polytope
lucaperju 0394b98
minor changes
lucaperju 6fe2cf5
fix bug, update set_interior_point function
lucaperju 52c731e
check that interior point is valid
lucaperju File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,3 +9,4 @@ test/Testing/Temporary/CTestCostData.txt | |
build/ | ||
.vscode | ||
.DS_Store | ||
.cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,23 +41,27 @@ 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 +72,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 +94,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,41 +110,60 @@ 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) | ||
{ | ||
_inner_ball.first = r; | ||
if(!is_in(r)) { | ||
std::cerr << "point outside of polytope was set as interior point" << std::endl; | ||
has_ball = false; | ||
return; | ||
} | ||
if(is_normalized()) { | ||
_inner_ball.second = (b - A * r.getCoefficients()).minCoeff(); | ||
} else { | ||
_inner_ball.second = std::numeric_limits<NT>::max(); | ||
for(int i = 0; i < num_of_hyperplanes(); ++i) { | ||
NT dist = (b(i) - A.row(i).dot(r.getCoefficients()) ) / A.row(i).norm(); | ||
if(dist < _inner_ball.second) { | ||
_inner_ball.second = dist; | ||
} | ||
} | ||
} | ||
has_ball = true; | ||
} | ||
|
||
//Compute Chebyshev ball of H-polytope P:= Ax<=b | ||
//Use LpSolve library | ||
//First try using max_inscribed_ball | ||
//Use LpSolve library if it fails | ||
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 +214,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 +241,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; | ||
} | ||
|
@@ -493,7 +524,7 @@ class HPolytope { | |
VT& Ar, | ||
VT& Av, | ||
NT const& lambda_prev, | ||
MT const& AA, | ||
DenseMT const& AA, | ||
update_parameters& params) const | ||
{ | ||
|
||
|
@@ -509,7 +540,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() += ((-2.0 * inner_prev) * AA.col(params.facet_prev)); | ||
} | ||
sum_nom.noalias() = b - Ar; | ||
|
||
|
@@ -630,12 +661,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 +857,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 +875,7 @@ class HPolytope { | |
void shift(const VT &c) | ||
{ | ||
b -= A*c; | ||
has_ball = false; | ||
} | ||
|
||
|
||
|
@@ -867,12 +905,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 +960,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(); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Can you add a TODO here to fix this function?
Because when we change the center of the inner ball we also need to change its radius.
Also the has_ball should be set to false here, right?
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.
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.
edit: oh, if you're refering the the set_interior_point function, then yeah, has_ball should likely be set to false, but I don't really know how we could fix this function further than that
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.
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||.
Check also the function
get_dists()
below; it returns the distance from the origin to each facet.