Boost C++ Libraries: Ticket #5561: error on calculating interval_map intersection https://svn.boost.org/trac10/ticket/5561 <p> here is the test case, reproducible with boost 1.46.1 and the today trunk. </p> <pre class="wiki">#include &lt;iostream&gt; #include &lt;assert.h&gt; #include &lt;boost/icl/interval_set.hpp&gt; #include &lt;boost/icl/interval_map.hpp&gt; int main() { typedef boost::icl::interval_map&lt;int, boost::icl::interval_set&lt;int&gt;&gt; I1; I1 i(std::make_pair(0, 100)), j(std::make_pair(0, 200)); std::cout &lt;&lt; i &lt;&lt; std::endl; // {([0,0]-&gt;{[100,100]})} std::cout &lt;&lt; j &lt;&lt; std::endl; // {([0,0]-&gt;{[200,200]})} std::cout &lt;&lt; (i+j) &lt;&lt; std::endl; // {([0,0]-&gt;{[100,100][200,200]})} std::cout &lt;&lt; (i-j) &lt;&lt; std::endl; // {([0,0]-&gt;{[100,100]})} std::cout &lt;&lt; (i&amp;j) &lt;&lt; std::endl; // {} assert((i&amp;j).empty()); // suppose to work same way as the test above typedef boost::icl::interval_map&lt;int, boost::icl::interval_map&lt;int, int&gt;&gt; I2; I2 k(std::make_pair(0, std::make_pair(100, 1))), l(std::make_pair(0, std::make_pair(200, 1))); std::cout &lt;&lt; k &lt;&lt; std::endl; // {([0,0]-&gt;{([100,100]-&gt;1)})} std::cout &lt;&lt; l &lt;&lt; std::endl; // {([0,0]-&gt;{([200,200]-&gt;1)})} std::cout &lt;&lt; (k+l) &lt;&lt; std::endl; // {([0,0]-&gt;{([100,100]-&gt;1)([200,200]-&gt;1)})} std::cout &lt;&lt; (k-l) &lt;&lt; std::endl; // {([0,0]-&gt;{([100,100]-&gt;1)})} std::cout &lt;&lt; (k&amp;l) &lt;&lt; std::endl; // {([0,0]-&gt;{([100,100]-&gt;1)([200,200]-&gt;1)})} while expecting {} assert((k&amp;l).empty()); } </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/5561 Trac 1.4.3 Joachim Faulhaber Wed, 25 May 2011 12:56:27 GMT <link>https://svn.boost.org/trac10/ticket/5561#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/5561#comment:1</guid> <description> <p> Hi Denis, </p> <p> as already mentioned in private mail, the behavior that you consider erroneous is correct and follows the specification (see docs). Since interval_maps perform aggregation on overlap, they pass a type's combine-operation to combine associated values for <code>+</code> and they pass a type's intersecting operation to intersect associated values on overlap, if an intersection is called on the interval_map. </p> <p> This is only possible if the type of the associated values (codomain_type) implements an intersection operation for operator &amp;. </p> <p> so </p> <table class="wiki"> <tr><td style="text-align: left"><code>Q = interval_map&lt;T, Numeric&gt;</code> </td><td style="text-align: left">is a Quantifier not having set semantics </td></tr><tr><td style="text-align: left"><code>interval_map&lt;T, Q&gt;</code> </td><td style="text-align: left">is a Quantifier not having set semantics </td></tr><tr><td style="text-align: left"><code>C = interval_map&lt;T, Set&gt;</code> </td><td style="text-align: left">is a Collector that has set semantics </td></tr><tr><td style="text-align: left"><code>interval_map&lt;T, C&gt;</code> </td><td style="text-align: left">is a Collector that has set semantics </td></tr></table> <p> For Quantifiers, the intersection operations &amp; degenerates to +. </p> <p> See also <a class="ext-link" href="http://www.joachim-faulhaber.de/boost_icl/doc/libs/icl/doc/html/boost_icl/semantics/collectors__maps_of_sets.html"><span class="icon">​</span>http://www.joachim-faulhaber.de/boost_icl/doc/libs/icl/doc/html/boost_icl/semantics/collectors__maps_of_sets.html</a> </p> <p> <a class="ext-link" href="http://www.joachim-faulhaber.de/boost_icl/doc/libs/icl/doc/html/boost_icl/semantics/quantifiers__maps_of_numbers.html"><span class="icon">​</span>http://www.joachim-faulhaber.de/boost_icl/doc/libs/icl/doc/html/boost_icl/semantics/quantifiers__maps_of_numbers.html</a> </p> <p> What you always can do is this </p> <div class="wiki-code"><div class="code"><pre> <span class="c1">//Define a user defined type ...</span> <span class="k">class</span> <span class="nc">MySettic</span> <span class="p">{</span> <span class="c1">// Has some kind of intersection</span> <span class="n">MySettic</span><span class="o">&amp;</span> <span class="k">operator</span> <span class="o">&amp;=</span> <span class="p">(</span><span class="k">const</span> <span class="n">MySettic</span><span class="o">&amp;</span> <span class="n">rhs</span><span class="p">){...};</span> <span class="p">.</span> <span class="p">.</span> <span class="p">.</span> <span class="p">};</span> <span class="c1">//... make it have set semantics by partial specialization </span> <span class="c1">//of template icl::is_set</span> <span class="k">namespace</span> <span class="n">boost</span><span class="p">{</span> <span class="k">namespace</span> <span class="n">icl</span> <span class="p">{</span> <span class="k">struct</span> <span class="n">is_set</span><span class="o">&lt;</span><span class="n">MySettic</span><span class="o">&gt;</span> <span class="p">{</span> <span class="k">typedef</span> <span class="n">is_set</span><span class="o">&lt;</span><span class="n">bits</span><span class="o">&lt;</span><span class="n">NaturalT</span><span class="o">&gt;</span> <span class="o">&gt;</span> <span class="n">type</span><span class="p">;</span> <span class="n">BOOST_STATIC_CONSTANT</span><span class="p">(</span><span class="kt">bool</span><span class="p">,</span> <span class="n">value</span> <span class="o">=</span> <span class="nb">true</span><span class="p">);</span> <span class="p">};</span> <span class="p">}</span> <span class="p">}</span> <span class="c1">//... and then use it in your interval maps.</span> <span class="n">interval_map</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">MySettic</span><span class="o">&gt;</span> <span class="n">myIMap</span><span class="p">;</span> </pre></div></div><p> HTH, Best regards, </p> <p> Joachim </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joachim Faulhaber</dc:creator> <pubDate>Wed, 25 May 2011 12:57:10 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/5561#comment:2 https://svn.boost.org/trac10/ticket/5561#comment:2 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">invalid</span> </li> </ul> Ticket denis@… Tue, 31 May 2011 13:19:23 GMT <link>https://svn.boost.org/trac10/ticket/5561#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/5561#comment:3</guid> <description> <p> You solution is nice, but it not only enables set semantic but allows Icl to assume that codomain is an iterable container. And Icl uses iteration to perform some operations (for example <code> operator^() </code> ). What I want is to have a codomain with set semantic without exposing its internals. It might have a container inside but also might not have. One example of such codomain is bool (or fixed-length array of bool). Another is AST tree. Below is code of exampled <a class="missing wiki">MySettic</a> which exposes its intersection/union/difference interface but not the iteration interface. What is the recommended way to use it as a interval_map's codomain? </p> <pre class="wiki">class MySettic { uint32_t set_; friend std::ostream&amp; operator &lt;&lt;(std::ostream&amp;, const MySettic&amp;); public: MySettic() {} MySettic(int a, int b) { set_ = (1&lt;&lt;a) | (1&lt;&lt;b); } bool operator == (const MySettic&amp; rhs) const { return set_ == rhs.set_; } MySettic&amp; operator &amp;= (const MySettic&amp; rhs){ set_ &amp;= rhs.set_; return *this ; }; MySettic&amp; operator -= (const MySettic&amp; rhs){ set_ &amp;= ~rhs.set_; return *this ; }; MySettic&amp; operator ^= (const MySettic&amp; rhs){ set_ ^= rhs.set_; return *this ; }; MySettic&amp; operator += (const MySettic&amp; rhs){ set_ |= rhs.set_; return *this ; }; }; std::ostream&amp; operator &lt;&lt;(std::ostream&amp; o, const MySettic&amp; ms) { bool needspace=false; for(int i=0; i&lt;32; i++) if(ms.set_ &amp; (1&lt;&lt;i)) { if(needspace++) o &lt;&lt; " "; o &lt;&lt; i; } return o; } class fmt { std::ostringstream ss; public: operator std::ostringstream&amp;() {return ss;} operator std::string() const {return ss.str();} template&lt;typename T&gt; fmt&amp; operator&lt;&lt;(T const&amp; v) {ss&lt;&lt;v; return *this;} }; TEST(IntervalMap, MyCodomainSetSemantic) { MySettic s1(1,6), s2(1,12), s3; #ifdef TMP_FIX // it solves the issue partially, '|' '&amp;' '-' work, but '^' fails icl::interval_map&lt;int, MySettic, icl::partial_absorber, // default ICL_COMPARE_INSTANCE(std::less, DomainT), // default ICL_COMBINE_INSTANCE(icl::inplace_plus, MySettic), // default ICL_SECTION_INSTANCE(icl::inplace_et, MySettic) &gt; m1, m2; #else icl::interval_map&lt;int, MySettic&gt; m1, m2; #endif m1.add(make_pair(icl::interval&lt;int&gt;::closed(1,10), s1)); m2.add(make_pair(icl::interval&lt;int&gt;::closed(5,15), s2)); EXPECT_EQ("1 6 12", std::string(fmt() &lt;&lt; ((s3=s1)+=s2))); EXPECT_EQ("1", std::string(fmt() &lt;&lt; ((s3=s1)&amp;=s2))); EXPECT_EQ("6", std::string(fmt() &lt;&lt; ((s3=s1)-=s2))); EXPECT_EQ("6 12", std::string(fmt() &lt;&lt; ((s3=s1)^=s2))); EXPECT_EQ("{([1,5)-&gt;1 6)([5,10]-&gt;1 6 12)((10,15]-&gt;1 12)}", std::string(fmt() &lt;&lt; (m1|m2))); EXPECT_EQ("{([5,10]-&gt;1)}", std::string(fmt() &lt;&lt; (m1&amp;m2))); EXPECT_EQ("{([1,5)-&gt;1 6)([5,10]-&gt;6)}", std::string(fmt() &lt;&lt; (m1-m2))); EXPECT_EQ("{([1,5)-&gt;1 6)([5,10]-&gt;6 12)((10,15]-&gt;1 12)}", std::string(fmt() &lt;&lt; (m1^m2))); // wrong with TMP_FIX } </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Joachim Faulhaber</dc:creator> <pubDate>Mon, 06 Jun 2011 12:29:33 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/5561#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/5561#comment:4</guid> <description> <p> Hi Denis, </p> <p> this is advanced usage of the ICL and as stated before, it is interesting for me <strong>and others</strong> to see how my library can be used in creative ways. So <strong>please</strong> lead this kind of communication on the boost developers list from the beginning. Sometimes we are entering use cases here, that are a kind of complex and we are running the risk of making errors. </p> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/5561#comment:3" title="Comment 3">denis@…</a>: </p> <blockquote class="citation"> <p> You solution is nice, but it not only enables set semantic but allows Icl to assume that codomain is an iterable container. And Icl uses iteration to perform some operations (for example <code> operator^() </code> ). What I want is to have a codomain with set semantic without exposing its internals. It might have a container inside but also might not have. One example of such codomain is bool (or fixed-length array of bool). Another is AST tree. </p> </blockquote> <p> I think my solution works and you were running into some problems by doing something wrong. One of those errors is to use a codomain type that leaves its value undefined on default construction. (See below). Another problem is that you did not instantiate template <code>icl::is_set</code> for the custom codomain type <code>MySettic</code>, as suggested. </p> <blockquote class="citation"> <p> Below is code of exampled <a class="missing wiki">MySettic</a> which exposes its intersection/union/difference interface but not the iteration interface. What is the recommended way to use it as a interval_map's codomain? </p> <pre class="wiki">class MySettic { uint32_t set_; friend std::ostream&amp; operator &lt;&lt;(std::ostream&amp;, const MySettic&amp;); public: </pre></blockquote> <p> <em>Problem: Undefined default-ctor </em></p> <blockquote class="citation"> <pre class="wiki"> MySettic() {} MySettic(int a, int b) { set_ = (1&lt;&lt;a) | (1&lt;&lt;b); } bool operator == (const MySettic&amp; rhs) const { return set_ == rhs.set_; } MySettic&amp; operator &amp;= (const MySettic&amp; rhs){ set_ &amp;= rhs.set_; return *this ; }; MySettic&amp; operator -= (const MySettic&amp; rhs){ set_ &amp;= ~rhs.set_; return *this ; }; MySettic&amp; operator ^= (const MySettic&amp; rhs){ set_ ^= rhs.set_; return *this ; }; MySettic&amp; operator += (const MySettic&amp; rhs){ set_ |= rhs.set_; return *this ; }; }; std::ostream&amp; operator &lt;&lt;(std::ostream&amp; o, const MySettic&amp; ms) { bool needspace=false; for(int i=0; i&lt;32; i++) if(ms.set_ &amp; (1&lt;&lt;i)) { if(needspace++) o &lt;&lt; " "; o &lt;&lt; i; } return o; } class fmt { std::ostringstream ss; public: operator std::ostringstream&amp;() {return ss;} operator std::string() const {return ss.str();} template&lt;typename T&gt; fmt&amp; operator&lt;&lt;(T const&amp; v) {ss&lt;&lt;v; return *this;} }; TEST(IntervalMap, MyCodomainSetSemantic) { MySettic s1(1,6), s2(1,12), s3; #ifdef TMP_FIX // it solves the issue partially, '|' '&amp;' '-' work, but '^' fails icl::interval_map&lt;int, MySettic, icl::partial_absorber, // default ICL_COMPARE_INSTANCE(std::less, DomainT), // default ICL_COMBINE_INSTANCE(icl::inplace_plus, MySettic), // default ICL_SECTION_INSTANCE(icl::inplace_et, MySettic) &gt; m1, m2; #else icl::interval_map&lt;int, MySettic&gt; m1, m2; #endif m1.add(make_pair(icl::interval&lt;int&gt;::closed(1,10), s1)); m2.add(make_pair(icl::interval&lt;int&gt;::closed(5,15), s2)); EXPECT_EQ("1 6 12", std::string(fmt() &lt;&lt; ((s3=s1)+=s2))); EXPECT_EQ("1", std::string(fmt() &lt;&lt; ((s3=s1)&amp;=s2))); EXPECT_EQ("6", std::string(fmt() &lt;&lt; ((s3=s1)-=s2))); EXPECT_EQ("6 12", std::string(fmt() &lt;&lt; ((s3=s1)^=s2))); EXPECT_EQ("{([1,5)-&gt;1 6)([5,10]-&gt;1 6 12)((10,15]-&gt;1 12)}", std::string(fmt() &lt;&lt; (m1|m2))); EXPECT_EQ("{([5,10]-&gt;1)}", std::string(fmt() &lt;&lt; (m1&amp;m2))); EXPECT_EQ("{([1,5)-&gt;1 6)([5,10]-&gt;6)}", std::string(fmt() &lt;&lt; (m1-m2))); EXPECT_EQ("{([1,5)-&gt;1 6)([5,10]-&gt;6 12)((10,15]-&gt;1 12)}", std::string(fmt() &lt;&lt; (m1^m2))); // wrong with TMP_FIX } </pre></blockquote> <p> I am giving the modified source code for <code>MySettic</code> in which all operations work as expected: </p> <pre class="wiki">//============================================================================== class MySettic { uint32_t set_; friend std::ostream&amp; operator &lt;&lt;(std::ostream&amp;, const MySettic&amp;); public: // ADDED // When working with ICL the default ctor *must not* be undefined. // Always implememetn it so it represents the identity element w.r.t. // your major combining operation (which is += or |= implementing // set union in this case. MySettic(): set_(0u){} // ADDED MySettic(uint32_t bits): set_(bits){} MySettic(int a, int b) { set_ = (1&lt;&lt;a) | (1&lt;&lt;b); } bool operator == (const MySettic&amp; rhs) const { return set_ == rhs.set_; } MySettic&amp; operator &amp;= (const MySettic&amp; rhs){ set_ &amp;= rhs.set_; return *this ; }; MySettic&amp; operator -= (const MySettic&amp; rhs){ set_ &amp;= ~rhs.set_; return *this ; }; MySettic&amp; operator ^= (const MySettic&amp; rhs){ set_ ^= rhs.set_; return *this ; }; MySettic&amp; operator += (const MySettic&amp; rhs){ set_ |= rhs.set_; return *this ; }; //ADDED MySettic&amp; operator |= (const MySettic&amp; rhs){ set_ |= rhs.set_; return *this ; }; //ADDED MySettic operator ~ ()const { return MySettic(~set_); } }; std::ostream&amp; operator &lt;&lt;(std::ostream&amp; o, const MySettic&amp; ms) { bool needspace=false; for(int i=0; i&lt;32; i++) if(ms.set_ &amp; (1&lt;&lt;i)) { if(needspace++) o &lt;&lt; " "; o &lt;&lt; i; } return o; } class fmt { std::ostringstream ss; public: operator std::ostringstream&amp;() {return ss;} operator std::string() const {return ss.str();} template&lt;typename T&gt; fmt&amp; operator&lt;&lt;(T const&amp; v) {ss&lt;&lt;v; return *this;} }; // ADDED // You *have to* instantiate template icl::is_set for you custom type, // to achive set semantic behavior of interval_maps. template&lt;&gt; struct is_set&lt;MySettic&gt; { typedef is_set&lt;MySettic&gt; type; BOOST_STATIC_CONSTANT(bool, value = true); }; BOOST_AUTO_TEST_CASE(settic_codomain_4_denis) { MySettic s1(1,6), s2(1,12); cout &lt;&lt; "symptomic_difference ---------" &lt;&lt; endl; cout &lt;&lt; "s1=" &lt;&lt; s1 &lt;&lt; endl; cout &lt;&lt; "s2=" &lt;&lt; s2 &lt;&lt; endl; cout &lt;&lt; "s1^s2=" &lt;&lt; (s1^s2) &lt;&lt; endl; // Working with a type like this is not a FIX as your posting impies // but proper advanced usage of interval containers. typedef interval_map&lt;int, MySettic, partial_absorber, std::less, inplace_bit_add, inplace_bit_and&gt; BitCollectorT; // This type works properly as well but you have to implement += via |= // which is done for MySettic. typedef interval_map&lt;int, MySettic, partial_absorber, std::less, inplace_plus, inplace_et&gt; BitCollector2T; BitCollectorT m1, m2; m1.add(make_pair(icl::interval&lt;int&gt;::closed(1,10), s1)); m2.add(make_pair(icl::interval&lt;int&gt;::closed(5,15), s2)); cout &lt;&lt; "m1:" &lt;&lt; m1 &lt;&lt; endl; cout &lt;&lt; "m2:" &lt;&lt; m2 &lt;&lt; endl; cout &lt;&lt; "m1^m2:" &lt;&lt; (m1^m2) &lt;&lt; endl; } //============================================================================== </pre><p> As you can see, there is still no bug on the library's side, so the ticket stays closed. </p> <p> Thank you again for you valuable use cases and comments. </p> <p> Joachim </p> </description> <category>Ticket</category> </item> </channel> </rss>