Skip to content
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

max_inscribed_ellipsoid takes too much time #179

Closed
vaithak opened this issue Sep 22, 2021 · 4 comments
Closed

max_inscribed_ellipsoid takes too much time #179

vaithak opened this issue Sep 22, 2021 · 4 comments

Comments

@vaithak
Copy link
Collaborator

vaithak commented Sep 22, 2021

Describe the bug
I am trying to (approximately) compute the number of linear extensions of a poset by computing the volume of it's corresponding order polytope.
My poset instance has 100 dimensions and has the following adjacency matrix: link to the file

The instance is taken from this repo, when run with the ARMC algorithm given in the same repo, it takes around 1.6 secs to compute the approximate answer (3.5e+129).
I tried using the volume algorithms implemented in volesti to compare the results.

  • First attempt
    • Rounding: None
    • Algorithm: Volume Cooling Balls
    • Result: 3.2e+129
    • Time taken: 15 secs
  • Next attempt: with rounding
    • Rounding: Computed the max inscribed ellipsoid to round the order polytope
    • Algorithm: Volume Cooling Balls
    • Result: 3.15e+129
    • Time taken: 17 mins 30 secs

As, can be seen from the results above, both attempts gave pretty accurate results but the time taken is drastically different ?
What am I doing wrong ?

To Reproduce

  • Code snipper for first attempt (without rounding)
#include "Eigen/Eigen"
#include <vector>
#include "cartesian_geom/cartesian_kernel.h"
#include "convex_bodies/hpolytope.h"
#include "convex_bodies/ellipsoid.h"
#include "preprocess/max_inscribed_ellipsoid.hpp"
#include "random_walks/uniform_billiard_walk.hpp"
#include "random_walks/uniform_accelerated_billiard_walk.hpp"
#include "generators/boost_random_number_generator.hpp"
#include "volume/volume_cooling_balls.hpp"

#include <iostream>
#include <fstream>
#include "misc.h"
#include "poset.h"

typedef double NT;
typedef Cartesian <NT> Kernel;
typedef typename Kernel::Point Point;
typedef BoostRandomNumberGenerator<boost::mt19937, NT> RNGType;
typedef HPolytope<Point> HPOLYTOPE;
typedef Ellipsoid<Point> EllipsoidType;
typedef typename HPOLYTOPE::MT MT;
typedef typename HPOLYTOPE::VT VT;

NT calculateLinearExtension(HPOLYTOPE& HP) {
    // Setup parameters for calculating volume and rounding
    unsigned int d = HP.dimension();
    unsigned int walk_len = 1;
    NT e = 0.1;
    NT round_val = 1.0;

    NT volume = volume_cooling_balls<BilliardWalk, RNGType>(HP, e, walk_len).second;
    volume = volume * round_val;

    // multiplying by d factorial, d = number of elements
    for(NT i=(NT)d; i>1; i-=1) {
        volume = volume * i;
    }

    return volume;
}


/**

 Usage: ./cle INSTANCE

 example:
    ./cle instances/bipartite_0.5_008_0.txt

*/
int main(int argc, char* argv[]) {
    std::string filename (argv[1]);
    std::ifstream in;
    in.open(filename);
    std::pair<bool, Poset> read_poset = read_poset_from_file_adj_matrix(in);

    if( !read_poset.first ) {
        std::cerr << "error in reading data from file" << std::endl;
        return -1;
    }

    // ---------------- Create HPOLYTOPE ---------------------
    Poset poset = read_poset.second;
    int num_relations = poset.num_relations();
    int d = poset.num_elem();

    MT A = Eigen::MatrixXd::Zero(2*d + num_relations, d);
    VT b = Eigen::MatrixXd::Zero(2*d + num_relations, 1);

    // first add (ai >= 0) or (-ai <= 0) rows
    A.topLeftCorner(d, d) = -Eigen::MatrixXd::Identity(d, d);

    // next add (ai <= 1) rows
    A.block(d, 0, d, d) = Eigen::MatrixXd::Identity(d, d);
    b.block(d, 0, d, 1) = Eigen::MatrixXd::Constant(d, 1, 1.0);

    // next add the relations
    for(int idx=0; idx<num_relations; ++idx) {
        std::pair<int, int> edge  = poset.get_relation(idx);
        A(2*d + idx, edge.first)  = 1;
        A(2*d + idx, edge.second) = -1;
    }
    HPOLYTOPE HP(d, A, b);
    //--------------------------------------------------------

    std::cout << calculateLinearExtension(HP) << std::endl;
    return 0;
}
  • Code snippet for second attempt (with rounding)
#include "Eigen/Eigen"
#include <vector>
#include "cartesian_geom/cartesian_kernel.h"
#include "convex_bodies/hpolytope.h"
#include "convex_bodies/ellipsoid.h"
#include "preprocess/max_inscribed_ellipsoid.hpp"
#include "random_walks/uniform_billiard_walk.hpp"
#include "random_walks/uniform_accelerated_billiard_walk.hpp"
#include "generators/boost_random_number_generator.hpp"
#include "volume/volume_cooling_balls.hpp"

#include <iostream>
#include <fstream>
#include "misc.h"
#include "poset.h"

typedef double NT;
typedef Cartesian <NT> Kernel;
typedef typename Kernel::Point Point;
typedef BoostRandomNumberGenerator<boost::mt19937, NT> RNGType;
typedef HPolytope<Point> HPOLYTOPE;
typedef Ellipsoid<Point> EllipsoidType;
typedef typename HPOLYTOPE::MT MT;
typedef typename HPOLYTOPE::VT VT;

NT calculateLinearExtension(HPOLYTOPE& HP) {
    // Setup parameters for calculating volume and rounding
    unsigned int d = HP.dimension();
    unsigned int walk_len = 1;
    NT e = 0.1;
    NT round_val = 1.0;

    // ------------ START: max inscribed ellipsoid rounding ----------------------------------------------
    unsigned int max_iter = 150;
    NT tol = std::pow(10, -6.0), reg = std::pow(10, -4.0);

    std::pair<Point, NT> innerBall = HP.ComputeInnerBall();
    if (innerBall.second < 0.0)
        throw std::runtime_error("no inscribed ball");

    VT x0 = innerBall.first.getCoefficients();
    Eigen::SparseMatrix<NT> A = HP.get_mat().sparseView();
    std::pair<std::pair<MT, VT>, bool> inscribed_ellipsoid_res = max_inscribed_ellipsoid<MT>(A,
                                                                                             HP.get_vec(),
                                                                                             x0,
                                                                                             max_iter,
                                                                                             tol,
                                                                                             reg);

    if (!inscribed_ellipsoid_res.second) // not converged
        throw std::runtime_error("no inscribed ellipsoid");

    MT A_ell = inscribed_ellipsoid_res.first.first.inverse();
    EllipsoidType inscribed_ellipsoid( A_ell );
    MT L = inscribed_ellipsoid.Lcov();

    HP.shift(inscribed_ellipsoid_res.first.second);
    round_val = L.transpose().determinant();
    HP.linear_transformIt(L);
    // ------------ END: max inscribed ellipsoid rounding ------------------------------------------------

    NT volume = volume_cooling_balls<BilliardWalk, RNGType>(HP, e, walk_len).second;
    volume = volume * round_val;

    // multiplying by d factorial, d = number of elements
    for(NT i=(NT)d; i>1; i-=1) {
        volume = volume * i;
    }

    return volume;
}


/**

 Usage: ./cle INSTANCE

 example:
    ./cle instances/bipartite_0.5_008_0.txt

*/
int main(int argc, char* argv[]) {
    std::string filename (argv[1]);
    std::ifstream in;
    in.open(filename);
    std::pair<bool, Poset> read_poset = read_poset_from_file_adj_matrix(in);

    if( !read_poset.first ) {
        std::cerr << "error in reading data from file" << std::endl;
        return -1;
    }

    // ---------------- Create HPOLYTOPE ---------------------
    Poset poset = read_poset.second;
    int num_relations = poset.num_relations();
    int d = poset.num_elem();

    MT A = Eigen::MatrixXd::Zero(2*d + num_relations, d);
    VT b = Eigen::MatrixXd::Zero(2*d + num_relations, 1);

    // first add (ai >= 0) or (-ai <= 0) rows
    A.topLeftCorner(d, d) = -Eigen::MatrixXd::Identity(d, d);

    // next add (ai <= 1) rows
    A.block(d, 0, d, d) = Eigen::MatrixXd::Identity(d, d);
    b.block(d, 0, d, 1) = Eigen::MatrixXd::Constant(d, 1, 1.0);

    // next add the relations
    for(int idx=0; idx<num_relations; ++idx) {
        std::pair<int, int> edge  = poset.get_relation(idx);
        A(2*d + idx, edge.first)  = 1;
        A(2*d + idx, edge.second) = -1;
    }
    HPOLYTOPE HP(d, A, b);
    //--------------------------------------------------------

    std::cout << calculateLinearExtension(HP) << std::endl;
    return 0;
}

Expected behavior
I expected that both the attempts will have comparable time and possibly rounding will improve the efficiency.

Desktop (please complete the following information):

  • OS: Ubuntu, macOS (tested on both)
@vaithak vaithak changed the title max_inscribed_ellipsoid takes too much time max_inscribed_ellipsoid takes too much time Sep 22, 2021
@vaithak vaithak changed the title max_inscribed_ellipsoid takes too much time max_inscribed_ellipsoid takes too much time Sep 22, 2021
@Sar-thak-3
Copy link

Hi could you kindly elaborate the issue, I would love to work on this issue!

@creataur
Copy link

Hi, I tried to reproduce this issue and was unable to do it.
The line NT volume = volume_cooling_balls<BilliardWalk, RNGType>(HP, e, walk_len).second; in the function NT calculateLinearExtension(HPOLYTOPE& HP) for Code File without Rounding, doesn't return and the code might enter an infinite loop from there somewhere in the code.
According to @vaithak , that code should take only 15 seconds to run.
I was trying to reproduce the error as part of my GSoC 2024 Application. I used the same code and using GDB I was able to pinpoint the line in given code where the issue arises.

@TolisChal
Copy link
Member

This issue was fixed by #309

@TolisChal
Copy link
Member

I'm closing this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants