Skip to content

Commit 7a0be2d

Browse files
committed
Rounding with vaidya barrier (#316)
* implement vaidya minimizer and hessian computation * implement unit tests and update documentation * resolve PR commits
1 parent ce61434 commit 7a0be2d

File tree

6 files changed

+132
-8
lines changed

6 files changed

+132
-8
lines changed

include/preprocess/barrier_center_ellipsoid.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@
2727
The volumetric center is the minimizer of the volumetric barrier function, i.e., the optimal
2828
solution of the following optimization problem,
2929
30-
\min logdet \nabla^2 f(x), where f(x) the log barrier function
30+
\min logdet \nabla^2 f(x), where f(x) the log barrier function
31+
32+
The Vaidya center is the minimizer of the Vaidya barrier function, i.e., the optimal
33+
solution of the following optimization problem,
34+
35+
\min logdet \nabla^2 f(x) + d/m f(x), where f(x) the log barrier function.
3136
3237
The function solves the problems by using the Newton method.
3338

include/preprocess/inscribed_ellipsoid_rounding.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ compute_inscribed_ellipsoid(Custom_MT A, VT b, VT const& x0,
2626
{
2727
return max_inscribed_ellipsoid<MT>(A, b, x0, maxiter, tol, reg);
2828
} else if constexpr (ellipsoid_type == EllipsoidType::LOG_BARRIER ||
29-
ellipsoid_type == EllipsoidType::VOLUMETRIC_BARRIER)
29+
ellipsoid_type == EllipsoidType::VOLUMETRIC_BARRIER ||
30+
ellipsoid_type == EllipsoidType::VAIDYA_BARRIER)
3031
{
3132
return barrier_center_ellipsoid_linear_ineq<MT, ellipsoid_type, NT>(A, b, x0);
3233
} else

include/preprocess/rounding_util_functions.hpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ enum EllipsoidType
2222
{
2323
MAX_ELLIPSOID = 1,
2424
LOG_BARRIER = 2,
25-
VOLUMETRIC_BARRIER = 3
25+
VOLUMETRIC_BARRIER = 3,
26+
VAIDYA_BARRIER = 4
2627
};
2728

2829
template <int T>
@@ -345,7 +346,8 @@ std::tuple<NT, NT> init_step()
345346
if constexpr (BarrierType == EllipsoidType::LOG_BARRIER)
346347
{
347348
return {NT(1), NT(0.99)};
348-
} else if constexpr (BarrierType == EllipsoidType::VOLUMETRIC_BARRIER)
349+
} else if constexpr (BarrierType == EllipsoidType::VOLUMETRIC_BARRIER ||
350+
BarrierType == EllipsoidType::VAIDYA_BARRIER)
349351
{
350352
return {NT(0.5), NT(0.4)};
351353
} else {
@@ -362,21 +364,44 @@ void get_barrier_hessian_grad(MT const& A, MT const& A_trans, VT const& b,
362364
b_Ax.noalias() = b - Ax;
363365
VT s = b_Ax.cwiseInverse();
364366
VT s_sq = s.cwiseProduct(s);
367+
VT sigma;
365368
// Hessian of the log-barrier function
366369
update_Atrans_Diag_A<NT>(H, A_trans, A, s_sq.asDiagonal());
370+
371+
if constexpr (BarrierType == EllipsoidType::VOLUMETRIC_BARRIER ||
372+
BarrierType == EllipsoidType::VAIDYA_BARRIER)
373+
{
374+
// Computing sigma(x)_i = (a_i^T H^{-1} a_i) / (b_i - a_i^Tx)^2
375+
MT_dense HA = solve_mat(llt, H, A_trans, obj_val);
376+
MT_dense aiHai = HA.transpose().cwiseProduct(A);
377+
sigma = (aiHai.rowwise().sum()).cwiseProduct(s_sq);
378+
}
379+
367380
if constexpr (BarrierType == EllipsoidType::LOG_BARRIER)
368381
{
369382
grad.noalias() = A_trans * s;
370383
} else if constexpr (BarrierType == EllipsoidType::VOLUMETRIC_BARRIER)
371384
{
372-
// Computing sigma(x)_i = (a_i^T H^{-1} a_i) / (b_i - a_i^Tx)^2
373-
MT_dense HA = solve_mat(llt, H, A_trans, obj_val);
374-
MT_dense aiHai = HA.transpose().cwiseProduct(A);
375-
VT sigma = (aiHai.rowwise().sum()).cwiseProduct(s_sq);
376385
// Gradient of the volumetric barrier function
377386
grad.noalias() = A_trans * (s.cwiseProduct(sigma));
378387
// Hessian of the volumetric barrier function
379388
update_Atrans_Diag_A<NT>(H, A_trans, A, s_sq.cwiseProduct(sigma).asDiagonal());
389+
} else if constexpr (BarrierType == EllipsoidType::VAIDYA_BARRIER)
390+
{
391+
const int m = b.size(), d = x.size();
392+
NT const d_m = NT(d) / NT(m);
393+
// Weighted gradient of the log barrier function
394+
grad.noalias() = A_trans * s;
395+
grad *= d_m;
396+
// Add the gradient of the volumetric function
397+
grad.noalias() += A_trans * (s.cwiseProduct(sigma));
398+
// Weighted Hessian of the log barrier function
399+
H *= d_m;
400+
// Add the Hessian of the volumetric function
401+
MT Hvol(d, d);
402+
update_Atrans_Diag_A<NT>(Hvol, A_trans, A, s_sq.cwiseProduct(sigma).asDiagonal());
403+
H += Hvol;
404+
obj_val -= s.array().log().sum();
380405
} else {
381406
static_assert(AssertBarrierFalseType<BarrierType>::value,
382407
"Barrier type is not supported.");
@@ -393,6 +418,9 @@ void get_step_next_iteration(NT const obj_val_prev, NT const obj_val,
393418
} else if constexpr (BarrierType == EllipsoidType::VOLUMETRIC_BARRIER)
394419
{
395420
step_iter *= (obj_val_prev <= obj_val - tol_obj) ? NT(0.9) : NT(0.999);
421+
} else if constexpr (BarrierType == EllipsoidType::VAIDYA_BARRIER)
422+
{
423+
step_iter *= NT(0.999);
396424
} else {
397425
static_assert(AssertBarrierFalseType<BarrierType>::value,
398426
"Barrier type is not supported.");

test/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ add_test(NAME round_max_ellipsoid_sparse
302302
COMMAND rounding_test -tc=round_max_ellipsoid_sparse)
303303
add_test(NAME round_volumetric_barrier_test
304304
COMMAND rounding_test -tc=round_volumetric_barrier_test)
305+
add_test(NAME round_vaidya_barrier_test
306+
COMMAND rounding_test -tc=round_vaidya_barrier_test)
305307

306308

307309

@@ -367,6 +369,8 @@ add_test(NAME test_max_ball_sparse
367369
COMMAND test_internal_points -tc=test_max_ball_sparse)
368370
add_test(NAME test_volumetric_center
369371
COMMAND test_internal_points -tc=test_volumetric_center)
372+
add_test(NAME test_vaidya_center
373+
COMMAND test_internal_points -tc=test_vaidya_center)
370374

371375

372376

test/rounding_test.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,37 @@ void rounding_volumetric_barrier_test(Polytope &HP,
228228
test_values(volume, expectedBilliard, exact);
229229
}
230230

231+
template <class Polytope>
232+
void rounding_vaidya_barrier_test(Polytope &HP,
233+
double const& expectedBall,
234+
double const& expectedCDHR,
235+
double const& expectedRDHR,
236+
double const& expectedBilliard,
237+
double const& exact)
238+
{
239+
typedef typename Polytope::PointType Point;
240+
typedef typename Point::FT NT;
241+
typedef typename Polytope::MT MT;
242+
typedef typename Polytope::VT VT;
243+
244+
int d = HP.dimension();
245+
246+
typedef BoostRandomNumberGenerator<boost::mt19937, NT, 5> RNGType;
247+
RNGType rng(d);
248+
249+
VT x0(d);
250+
x0 << 0.7566, 0.6374, 0.3981, 0.9248, 0.9828;
251+
std::tuple<MT, VT, NT> res = inscribed_ellipsoid_rounding<MT, VT, NT, Polytope, Point, EllipsoidType::VAIDYA_BARRIER>(HP, Point(x0));
252+
// Setup the parameters
253+
int walk_len = 1;
254+
NT e = 0.1;
255+
256+
// Estimate the volume
257+
std::cout << "Number type: " << typeid(NT).name() << std::endl;
258+
259+
NT volume = std::get<2>(res) * volume_cooling_balls<BilliardWalk, RNGType>(HP, e, walk_len).second;
260+
test_values(volume, expectedBilliard, exact);
261+
}
231262

232263
template <class Polytope>
233264
void rounding_svd_test(Polytope &HP,
@@ -326,6 +357,17 @@ void call_test_volumetric_barrier() {
326357
rounding_volumetric_barrier_test(P, 0, 3070.64, 3188.25, 3262.77, 3200.0);
327358
}
328359

360+
template <typename NT>
361+
void call_test_vaidya_barrier() {
362+
typedef Cartesian <NT> Kernel;
363+
typedef typename Kernel::Point Point;
364+
typedef HPolytope <Point> Hpolytope;
365+
Hpolytope P;
366+
367+
std::cout << "\n--- Testing vaidya barrier rounding of H-skinny_cube5" << std::endl;
368+
P = generate_skinny_cube<Hpolytope>(5);
369+
rounding_vaidya_barrier_test(P, 0, 3070.64, 3188.25, 3262.77, 3200.0);
370+
}
329371

330372
template <typename NT>
331373
void call_test_svd() {
@@ -360,6 +402,10 @@ TEST_CASE("round_volumetric_barrier_test") {
360402
call_test_volumetric_barrier<double>();
361403
}
362404

405+
TEST_CASE("round_vaidya_barrier_test") {
406+
call_test_vaidya_barrier<double>();
407+
}
408+
363409
TEST_CASE("round_svd") {
364410
call_test_svd<double>();
365411
}

test/test_internal_points.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,42 @@ void call_test_volumetric_center() {
184184
CHECK((Hessian - Hessian_sp).norm() < 1e-12);
185185
}
186186

187+
template <typename NT>
188+
void call_test_vaidya_center() {
189+
typedef Cartesian <NT> Kernel;
190+
typedef typename Kernel::Point Point;
191+
typedef HPolytope <Point> Hpolytope;
192+
typedef typename Hpolytope::MT MT;
193+
typedef typename Hpolytope::VT VT;
194+
typedef boost::mt19937 PolyRNGType;
195+
typedef Eigen::SparseMatrix<NT> SpMT;
196+
Hpolytope P;
197+
198+
std::cout << "\n--- Testing vaidya center for skinny H-polytope" << std::endl;
199+
bool pre_rounding = true; // round random polytope before applying the skinny transformation
200+
NT max_min_eig_ratio = NT(100);
201+
P = skinny_random_hpoly<Hpolytope, NT, PolyRNGType>(3, 15, pre_rounding, max_min_eig_ratio, 127);
202+
P.normalize();
203+
204+
auto [Hessian, vaidya_center, converged] = barrier_center_ellipsoid_linear_ineq<MT, EllipsoidType::VAIDYA_BARRIER, NT>(P.get_mat(), P.get_vec());
205+
SpMT Asp = P.get_mat().sparseView();
206+
auto [Hessian_sp, vaidya_center2, converged2] = barrier_center_ellipsoid_linear_ineq<MT, EllipsoidType::VAIDYA_BARRIER, NT>(Asp, P.get_vec());
207+
208+
CHECK(P.is_in(Point(vaidya_center)) == -1);
209+
CHECK(converged);
210+
CHECK(std::abs(vaidya_center(0) + 2.4076) < 1e-04);
211+
CHECK(std::abs(vaidya_center(1) + 2.34072) < 1e-04);
212+
CHECK(std::abs(vaidya_center(2) - 3.97138) < 1e-04);
213+
214+
CHECK(P.is_in(Point(vaidya_center2)) == -1);
215+
CHECK(converged2);
216+
CHECK(std::abs(vaidya_center(0) - vaidya_center2(0)) < 1e-12);
217+
CHECK(std::abs(vaidya_center(1) - vaidya_center2(1)) < 1e-12);
218+
CHECK(std::abs(vaidya_center(2) - vaidya_center2(2)) < 1e-12);
219+
220+
CHECK((Hessian - Hessian_sp).norm() < 1e-12);
221+
}
222+
187223
TEST_CASE("test_max_ball") {
188224
call_test_max_ball<double>();
189225
}
@@ -200,6 +236,10 @@ TEST_CASE("test_volumetric_center") {
200236
call_test_volumetric_center<double>();
201237
}
202238

239+
TEST_CASE("test_vaidya_center") {
240+
call_test_vaidya_center<double>();
241+
}
242+
203243
TEST_CASE("test_max_ball_sparse") {
204244
call_test_max_ball_sparse<double>();
205245
}

0 commit comments

Comments
 (0)