-
Notifications
You must be signed in to change notification settings - Fork 127
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
Generalize the rounding loop and support sparse computations in preprocessing routines #312
Changes from 8 commits
911e030
85b1faf
b3f75ba
7e66e8c
5df7093
d50b4cd
6051ebc
e27854b
25a39b1
4168002
960969c
da7348d
035cfe8
9b72f5f
11b4948
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 |
---|---|---|
|
@@ -73,16 +73,19 @@ void sample_using_gaussian_billiard_walk(HPOLYTOPE& HP, RNGType& rng, unsigned i | |
unsigned int max_iter = 150; | ||
NT tol = std::pow(10, -6.0), reg = std::pow(10, -4.0); | ||
VT x0 = q.getCoefficients(); | ||
std::pair<std::pair<MT, VT>, bool> inscribed_ellipsoid_res = max_inscribed_ellipsoid<MT>(HP.get_mat(), | ||
HP.get_vec(), | ||
x0, | ||
max_iter, | ||
tol, | ||
reg); | ||
if (!inscribed_ellipsoid_res.second) // not converged | ||
MT E; | ||
VT center; | ||
bool converged; | ||
std::tie(E, center, converged) = max_inscribed_ellipsoid<MT>(HP.get_mat(), | ||
HP.get_vec(), | ||
x0, | ||
max_iter, | ||
tol, | ||
reg); | ||
if (!converged) // not converged | ||
throw std::runtime_error("max_inscribed_ellipsoid not converged"); | ||
|
||
MT A_ell = inscribed_ellipsoid_res.first.first.inverse(); | ||
MT A_ell = E; | ||
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 we avoid the copy here? 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. Thanks, done |
||
EllipsoidType inscribed_ellipsoid(A_ell); | ||
// -------------------------------------------------------------------- | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -638,6 +638,12 @@ class OrderPolytope { | |
return false; | ||
} | ||
|
||
// Apply linear transformation, of square matrix T^{-1}, in H-polytope P:= Ax<=b | ||
// This is most of the times for testing reasons because it might destroy the sparsity | ||
void linear_transformIt(MT const& T) | ||
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. we should follow naming conventions here, so 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.
|
||
{ | ||
_A = _A * T; | ||
} | ||
|
||
// shift polytope by a point c | ||
void shift(VT const& c) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// VolEsti (volume computation and sampling library) | ||
|
||
// Copyright (c) 2024 Vissarion Fisikopoulos | ||
// Copyright (c) 2024 Apostolos Chalkis | ||
// Copyright (c) 2024 Elias Tsigaridas | ||
|
||
// Licensed under GNU LGPL.3, see LICENCE file | ||
|
||
|
||
#ifndef FEASIBLE_POINT_HPP | ||
#define FEASIBLE_POINT_HPP | ||
|
||
#include <tuple> | ||
|
||
#include "max_inscribed_ball.hpp" | ||
|
||
// Using MT as to deal with both dense and sparse matrices | ||
template <typename MT, typename VT> | ||
VT compute_feasible_point(MT const& A, VT const& b) | ||
{ | ||
VT x; | ||
bool feasibility_only = true, converged; | ||
unsigned max_iters = 10000; | ||
// Compute a feasible point | ||
std::tie(x, std::ignore, converged) = max_inscribed_ball(A, b, max_iters, 1e-08, feasibility_only); | ||
if (!converged || ((A * x).array() > b.array()).any()) | ||
{ | ||
std::runtime_error("The computation of a feasible point failed."); | ||
} | ||
return x; | ||
} | ||
|
||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
// VolEsti (volume computation and sampling library) | ||
|
||
// Copyright (c) 2012-2020 Vissarion Fisikopoulos | ||
// Copyright (c) 2018-2020 Apostolos Chalkis | ||
|
||
//Contributed and/or modified by Alexandros Manochis, as part of Google Summer of Code 2020 program. | ||
|
||
// Licensed under GNU LGPL.3, see LICENCE file | ||
|
||
|
||
#ifndef ELLIPSOID_ROUNDING_HPP | ||
#define ELLIPSOID_ROUNDING_HPP | ||
|
||
#include "max_inscribed_ellipsoid.hpp" | ||
#include "analytic_center_linear_ineq.h" | ||
#include "feasible_point.hpp" | ||
|
||
enum EllipsoidType | ||
{ | ||
MAX_ELLIPSOID = 1, | ||
LOG_BARRIER = 2 | ||
}; | ||
|
||
template<int C> | ||
struct inscribed_ellispoid | ||
{ | ||
template<typename MT, typename Custom_MT, typename VT, typename NT> | ||
inline static std::tuple<MT, VT, NT> | ||
compute(Custom_MT A, VT b, VT const& x0, | ||
unsigned int const& maxiter, | ||
NT const& tol, NT const& reg) | ||
{ | ||
std::runtime_error("No roudning method is defined"); | ||
return std::tuple<MT, VT, NT>(); | ||
} | ||
}; | ||
|
||
template <> | ||
struct inscribed_ellispoid<EllipsoidType::MAX_ELLIPSOID> | ||
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. Since we use C++17 it is simpler to replace those specializations with
inside 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. Indeed, I added a new function |
||
{ | ||
template<typename MT, typename Custom_MT, typename VT, typename NT> | ||
inline static std::tuple<MT, VT, NT> | ||
compute(Custom_MT A, VT b, VT const& x0, | ||
unsigned int const& maxiter, | ||
NT const& tol, NT const& reg) | ||
{ | ||
return max_inscribed_ellipsoid<MT>(A, b, x0, maxiter, tol, reg); | ||
} | ||
}; | ||
|
||
template <> | ||
struct inscribed_ellispoid<EllipsoidType::LOG_BARRIER> | ||
{ | ||
template<typename MT, typename Custom_MT, typename VT, typename NT> | ||
inline static std::tuple<MT, VT, NT> | ||
compute(Custom_MT const& A, VT const& b, VT const& x0, | ||
unsigned int const& maxiter, | ||
NT const& tol, NT&) | ||
{ | ||
return analytic_center_linear_ineq<MT, Custom_MT, VT, NT>(A, b, x0); | ||
} | ||
}; | ||
|
||
template | ||
< | ||
typename MT, | ||
typename VT, | ||
typename NT, | ||
typename Polytope, | ||
int ellipsopid_type = EllipsoidType::MAX_ELLIPSOID | ||
> | ||
std::tuple<MT, VT, NT> inscribed_ellipsoid_rounding(Polytope &P, | ||
unsigned int const max_iterations = 5, | ||
NT const max_eig_ratio = NT(6)) | ||
{ | ||
typedef typename Polytope::PointType Point; | ||
VT x = compute_feasible_point(P.get_mat(), P.get_vec()); | ||
return inscribed_ellipsoid_rounding<MT, VT, NT>(P, Point(x), max_iterations, max_eig_ratio); | ||
} | ||
|
||
template | ||
< | ||
typename MT, | ||
typename VT, | ||
typename NT, | ||
typename Polytope, | ||
typename Point, | ||
int ellipsopid_type = EllipsoidType::MAX_ELLIPSOID | ||
> | ||
std::tuple<MT, VT, NT> inscribed_ellipsoid_rounding(Polytope &P, | ||
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. does this function changes 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 didn't change anything here (remind you this was previously the It looks good to me I'd say. I don't see any reason to copy P and round it instead. |
||
Point const& InnerPoint, | ||
unsigned int const max_iterations = 5, | ||
NT const max_eig_ratio = NT(6)) | ||
{ | ||
VT x0 = InnerPoint.getCoefficients(), center; | ||
MT E, L; | ||
bool converged; | ||
unsigned int maxiter = 500, iter = 1, d = P.dimension(); | ||
|
||
NT R = 100.0, r = 1.0, tol = std::pow(10, -6.0), reg = std::pow(10, -4.0), round_val = 1.0; | ||
|
||
MT T = MT::Identity(d, d); | ||
VT shift = VT::Zero(d); | ||
|
||
while (true) | ||
{ | ||
// compute the desired inscribed ellipsoid in P | ||
std::tie(E, center, converged) = | ||
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. this could be written in 2 lines
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. thanks, done |
||
inscribed_ellispoid<ellipsopid_type>::template compute<MT>(P.get_mat(), P.get_vec(), | ||
x0, maxiter, tol, reg); | ||
E = (E + E.transpose()) / 2.0; | ||
E += MT::Identity(d, d)*std::pow(10, -8.0); //normalize E | ||
|
||
Eigen::LLT<MT> lltOfA(E.llt().solve(MT::Identity(E.cols(), E.cols()))); // compute the Cholesky decomposition of E^{-1} | ||
L = lltOfA.matrixL(); | ||
|
||
// computing eigenvalues of E | ||
Spectra::DenseSymMatProd<NT> op(E); | ||
// The value of ncv is chosen empirically | ||
Spectra::SymEigsSolver<NT, Spectra::SELECT_EIGENVALUE::BOTH_ENDS, | ||
Spectra::DenseSymMatProd<NT>> eigs(&op, 2, std::min(std::max(10, int(d)/5), int(d))); | ||
eigs.init(); | ||
int nconv = eigs.compute(); | ||
if (eigs.info() == Spectra::COMPUTATION_INFO::SUCCESSFUL) { | ||
R = 1.0 / eigs.eigenvalues().coeff(1); | ||
r = 1.0 / eigs.eigenvalues().coeff(0); | ||
} else { | ||
Eigen::SelfAdjointEigenSolver<MT> eigensolver(E); | ||
if (eigensolver.info() == Eigen::ComputationInfo::Success) { | ||
R = 1.0 / eigensolver.eigenvalues().coeff(0); | ||
r = 1.0 / eigensolver.eigenvalues().template tail<1>().value(); | ||
} else { | ||
std::runtime_error("Computations failed."); | ||
} | ||
} | ||
// shift polytope and apply the linear transformation on P | ||
P.shift(center); | ||
shift.noalias() += T * center; | ||
T.applyOnTheRight(L); // T = T * L; | ||
round_val *= L.transpose().determinant(); | ||
P.linear_transformIt(L); | ||
|
||
reg = std::max(reg / 10.0, std::pow(10, -10.0)); | ||
P.normalize(); | ||
x0 = VT::Zero(d); | ||
|
||
// check the roundness of the polytope | ||
if(((std::abs(R / r) <= max_eig_ratio && converged) || iter >= max_iterations)){ | ||
break; | ||
} | ||
|
||
iter++; | ||
} | ||
|
||
std::tuple<MT, VT, NT> result = std::make_tuple(T, shift, std::abs(round_val)); | ||
return result; | ||
} | ||
|
||
#endif |
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.
maybe better
to consume only 2 lines
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.
Thanks, done