Search code examples
c++boost

How do I use boost::icl::hull?


The following code doesn't work:

typedef boost::icl::interval_set<unsigned> bi_list_type;
typedef bi_list_type::value_type iv_type;
std::vector<iv_type> y;
iv_type x; // how to initialize this?

for (auto i : y)
{
  x = boost::icl::hull(x, i);
}

The problem is, that x is default constructed and thus in the end 0 is always the lower bound of x. Is there any better way to use boost::icl::hull? And if so, how could I know without asking here (the doc isn't helpful in this regard)?

(The std::vector is only an example, the interval creation happens actually inside the loop).


Solution

  • "a better way to use boost::icl::hull"

    That depends 100% on the desired goal.

    "(the doc isn't helpful in this regard)"

    The doc also doesn't know your goal; it only tells you operations you can use to reach the goal.

    I don't know your goal, but to me it looks very much like it's working:

    Live On Coliru

    #include <boost/icl/interval_set.hpp>
    #include <iostream>
    namespace icl = boost::icl;
    
    int main() {
        using iv_type = icl::discrete_interval<unsigned int, std::less>;
    
        iv_type h{};
    
        for (auto& i : {
            iv_type::open(0, 0),
            iv_type::left_open(5, 8),
            iv_type::right_open(4, 6),
            iv_type::closed(6, 7),
        }) {
            std::cout << "h: " << h << " adding " << i << "\n";
            h = hull(h, i);
        }
        std::cout << "h: " << h << "\n";
    }
    

    Prints

    h: [) adding ()
    h: [) adding (5,8]
    h: (5,8] adding [4,6)
    h: [4,8] adding [6,7]
    h: [4,8]
    

    Alternatives

    Since you mentioned interval_set perhaps you can do better:

    Live On Coliru

    #include <boost/icl/interval_set.hpp>
    #include <iostream>
    namespace icl = boost::icl;
    
    int main() {
        using set  = icl::interval_set<unsigned int>;
        using ival = set::value_type;
        auto s     = set{};
    
        s.add(ival::open(0, 0));
        s.add(ival::left_open(5, 8));
        s.add(ival::right_open(4, 6));
        s.add(ival::closed(6, 7));
    
        std::cout << "hull: " << hull(s) << "\n";
    }
    

    Printing

    hull: [4,8]
    

    Due to the orderedness of the set this does something different, I think. Which may or may not be what you want depending on the meaning/goal.

    Another Alternative

    If you really want the "left-fold" behaviour in sequence, but can't have an initializer like [) or [min(), max()) then perhaps write it as a left-fold:

    Live On Coliru

    #include <algorithm>
    #include <boost/icl/interval_set.hpp>
    #include <iostream>
    #include <numeric>
    namespace icl = boost::icl;
    
    int main() {
        using iv_type = icl::discrete_interval<unsigned int, std::less>;
        std::vector v{
            iv_type::open(0, 0),
            iv_type::left_open(5, 8),
            iv_type::right_open(4, 6),
            iv_type::closed(6, 7),
        };
    
        if (v.size()>0) {
            std::cout
              << "h: "
              << std::accumulate(begin(v) + 1, end(v), v.front(),
                    [](auto a, auto const& b) {
                        return icl::hull(std::move(a), b);
                    })
              << "\n";
        }
    }
    

    Which for our simple data still prints

    h: [4,8]