Boost C++ Libraries: Ticket #9126: Logistic distribution pdf() and cdf(complement()) fail to catch invalid scale and location parameters https://svn.boost.org/trac10/ticket/9126 <p> This issue is related to <strong>Ticket <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/9042" title="#9042: Bugs: boost::math, cdf(complement(normal_distribution&lt;&gt;(...)) fails to catch ... (closed: fixed)">#9042</a></strong> </p> <p> In <strong>boost/math/distributions/logistic.hpp</strong>: </p> <pre class="wiki"> template &lt;class RealType, class Policy&gt; inline RealType pdf(const logistic_distribution&lt;RealType, Policy&gt;&amp; dist, const RealType&amp; x) { RealType scale = dist.scale(); RealType location = dist.location(); static const char* function = "boost::math::pdf(const logistic_distribution&lt;%1%&gt;&amp;, %1%)"; if((boost::math::isinf)(x)) { return 0; // pdf + and - infinity is zero. } RealType result = 0; if(false == detail::check_scale(function, scale , &amp;result, Policy())) { return result; } if(false == detail::check_location(function, location, &amp;result, Policy())) { return result; } if(false == detail::check_x(function, x, &amp;result, Policy())) { return result; } BOOST_MATH_STD_USING RealType exp_term = (location - x) / scale; if(fabs(exp_term) &gt; tools::log_max_value&lt;RealType&gt;()) return 0; exp_term = exp(exp_term); if((exp_term * scale &gt; 1) &amp;&amp; (exp_term &gt; tools::max_value&lt;RealType&gt;() / (scale * exp_term))) return 1 / (scale * exp_term); return (exp_term) / (scale * (1 + exp_term) * (1 + exp_term)); } </pre><p> The test if((boost::math::isinf)(x)) occurs before check_scale() or check_location() is called, returning 0 for infinite x, even if scale or location are invalid. </p> <p> The calls to check_scale() and check_location() should be moved up just before the test if((boost::math::isinf)(x)). </p> <p> See, for example, how the tests are ordered here: </p> <pre class="wiki"> template &lt;class RealType, class Policy&gt; inline RealType cdf(const logistic_distribution&lt;RealType, Policy&gt;&amp; dist, const RealType&amp; x) { RealType scale = dist.scale(); RealType location = dist.location(); RealType result = 0; // of checks. static const char* function = "boost::math::cdf(const logistic_distribution&lt;%1%&gt;&amp;, %1%)"; if(false == detail::check_scale(function, scale, &amp;result, Policy())) { return result; } if(false == detail::check_location(function, location, &amp;result, Policy())) { return result; } if((boost::math::isinf)(x)) { if(x &lt; 0) return 0; // -infinity return 1; // + infinity } if(false == detail::check_x(function, x, &amp;result, Policy())) { return result; } BOOST_MATH_STD_USING RealType power = (location - x) / scale; if(power &gt; tools::log_max_value&lt;RealType&gt;()) return 0; if(power &lt; -tools::log_max_value&lt;RealType&gt;()) return 1; return 1 / (1 + exp(power)); } </pre><p> The same issue exists with the complementary cdf: </p> <pre class="wiki"> template &lt;class RealType, class Policy&gt; inline RealType cdf(const complemented2_type&lt;logistic_distribution&lt;RealType, Policy&gt;, RealType&gt;&amp; c) { BOOST_MATH_STD_USING RealType location = c.dist.location(); RealType scale = c.dist.scale(); RealType x = c.param; static const char* function = "boost::math::cdf(const complement(logistic_distribution&lt;%1%&gt;&amp;), %1%)"; if((boost::math::isinf)(x)) { if(x &lt; 0) return 1; // cdf complement -infinity is unity. return 0; // cdf complement +infinity is zero } RealType result = 0; if(false == detail::check_scale(function, scale, &amp;result, Policy())) return result; if(false == detail::check_location(function, location, &amp;result, Policy())) return result; if(false == detail::check_x(function, x, &amp;result, Policy())) return result; RealType power = (x - location) / scale; if(power &gt; tools::log_max_value&lt;RealType&gt;()) return 0; if(power &lt; -tools::log_max_value&lt;RealType&gt;()) return 1; return 1 / (1 + exp(power)); } </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/9126 Trac 1.4.3 Paul A. Bristow Wed, 18 Sep 2013 17:11:19 GMT owner, status, milestone changed https://svn.boost.org/trac10/ticket/9126#comment:1 https://svn.boost.org/trac10/ticket/9126#comment:1 <ul> <li><strong>owner</strong> changed from <span class="trac-author">John Maddock</span> to <span class="trac-author">Paul A. Bristow</span> </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.55.0</span> </li> </ul> <p> Thanks for reporting this which should be fixed for 1.55. </p> Ticket Paul A. Bristow Thu, 19 Sep 2013 13:07:44 GMT <link>https://svn.boost.org/trac10/ticket/9126#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9126#comment:2</guid> <description> <p> Have you an actual use example or test case for this condition (or is this comment just from examination of the code)? </p> </description> <category>Ticket</category> </item> <item> <author>Paul McClellan <paulm@…></author> <pubDate>Thu, 19 Sep 2013 15:41:21 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9126#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9126#comment:3</guid> <description> <p> I have wrappers around boost: </p> <pre class="wiki"> #include &lt;boost/math/distributions/logistic.hpp&gt; double logistic_pdf( double dX, double dL, double dS ) { // logistic distribution object: boost::math::logistic logis(dL, dS); return pdf(logis, dX); } double logistic_utp( double dX, double dL, double dS ) { // logistic distribution object: boost::math::logistic logis(dL, dS); return cdf(complement(logis, dX)); } </pre><p> These test cases should error, but return 0.0: </p> <pre class="wiki">logistic_pdf(Pc_PosInf, Pc_PosInf, 1.0); logistic_pdf(Pc_PosInf, 0.0, Pc_PosInf); logistic_pdf(Pc_PosInf, 0.0, 0.0); logistic_utp(Pc_PosInf, Pc_PosInf, 1.0); logistic_utp(Pc_PosInf, 0.0, Pc_PosInf); logistic_utp(Pc_PosInf, 0.0, 0.0); </pre> </description> <category>Ticket</category> </item> <item> <author>Paul McClellan <paulm@…></author> <pubDate>Thu, 19 Sep 2013 15:43:04 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9126#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9126#comment:4</guid> <description> <p> I should have included: </p> <pre class="wiki">#define Pc_PosInf (std::numeric_limits&lt;double&gt;::infinity()) </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Paul A. Bristow</dc:creator> <pubDate>Fri, 20 Sep 2013 09:47:33 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9126#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9126#comment:5</guid> <description> <p> Fixed in boost trunk at <a class="ext-link" href="https://svn.boost.org/svn/boost/trunk/boost/math/distributions/logistic.hpp"><span class="icon">​</span>https://svn.boost.org/svn/boost/trunk/boost/math/distributions/logistic.hpp</a> </p> <p> (you could download this version). </p> <p> SVN commit 87950 </p> <p> but I am still puzzled why the checks in the distribution object constructor didn't catch these tests. </p> <p> Did you change the default policy (from 'to throw exception') to ignore errors? </p> <p> Did you use try'n'catch blocks so that the error messages appear? (as always recommended). </p> <p> Did you get the same in debug and release (optimised) version? </p> <p> Should make boost release 1.55. </p> </description> <category>Ticket</category> </item> <item> <author>Paul McClellan <paulm@…></author> <pubDate>Fri, 20 Sep 2013 16:01:53 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9126#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9126#comment:6</guid> <description> <p> I apologize, I should have included my user.hpp settings. I've tried to attach my user.hpp file but Trac rejects it as spam. I've included the relevant portions here: </p> <pre class="wiki">// // Default policies follow: // // Domain errors: // // #define BOOST_MATH_DOMAIN_ERROR_POLICY throw_on_error #define BOOST_MATH_DOMAIN_ERROR_POLICY ignore_error // // Pole errors: // // #define BOOST_MATH_POLE_ERROR_POLICY throw_on_error #define BOOST_MATH_POLE_ERROR_POLICY ignore_error // // Overflow Errors: // // #define BOOST_MATH_OVERFLOW_ERROR_POLICY throw_on_error #define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error // // Internal Evaluation Errors: // // #define BOOST_MATH_EVALUATION_ERROR_POLICY throw_on_error #define BOOST_MATH_EVALUATION_ERROR_POLICY ignore_error // // Underfow: // // #define BOOST_MATH_UNDERFLOW_ERROR_POLICY ignore_error // // Denorms: // // #define BOOST_MATH_DENORM_ERROR_POLICY ignore_error // // Max digits to use for internal calculations: // // #define BOOST_MATH_DIGITS10_POLICY 0 // // Promote floats to doubles internally? // // #define BOOST_MATH_PROMOTE_FLOAT_POLICY true // // Promote doubles to long double internally: // // #define BOOST_MATH_PROMOTE_DOUBLE_POLICY true // // What do discrete quantiles return? // // #define BOOST_MATH_DISCRETE_QUANTILE_POLICY integer_round_outwards // // If a function is mathematically undefined // (for example the Cauchy distribution has no mean), // then do we stop the code from compiling? // // #define BOOST_MATH_ASSERT_UNDEFINED_POLICY true // // Maximum series iterstions permitted: // // #define BOOST_MATH_MAX_SERIES_ITERATION_POLICY 1000000 // // Maximum root finding steps permitted: // // define BOOST_MATH_MAX_ROOT_ITERATION_POLICY 200 // [PJM] Needed for students_t_ltq(), students_t_utq() // [PJM] changed with fix to Ticket #8837 //#define BOOST_MATH_ROUNDING_ERROR_POLICY ignore_error </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Paul A. Bristow</dc:creator> <pubDate>Mon, 23 Sep 2013 09:56:28 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9126#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9126#comment:7</guid> <description> <p> Ah ha, as I eventually suspected, you are ignoring the carefully constructed error reporting mechanism :-) </p> <p> I trust that the code changes will meet your wishes, but one could argue that the more correct result from 'bad' distribution constructor arguments is always NaN (not infinity). You could define your custom policy to achieve just that. Or you could use the default error handling policy and throw'n'catch from the distribution construction - the intended usage, as given in many examples. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>John Maddock</dc:creator> <pubDate>Sat, 28 Sep 2013 16:19:56 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9126#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9126#comment:8</guid> <description> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/85987" title="Merge accumulated patches from Trunk. Refs #8384, Refs #8855, refs ...">[85987]</a>) Merge accumulated patches from Trunk. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/8384" title="#8384: Feature Requests: Make shared_ptr movable (closed: invalid)">#8384</a>, Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/8855" title="#8855: Bugs: [math] GCC 4.8+ warns unused local typedef... (closed: fixed)">#8855</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/9107" title="#9107: Bugs: unused parameter warning in fraction with clang (closed: fixed)">#9107</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/9109" title="#9109: Bugs: Warning in bessel with -Wshadow (closed: fixed)">#9109</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/8333" title="#8333: Bugs: [math] PGI 11.3 problems (sph_bessel.cpp, sph_bessel.cpp) (closed: fixed)">#8333</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/8621" title="#8621: Bugs: erf function gives wrong results with pgcpp - PGI 10.4 (closed: fixed)">#8621</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/8732" title="#8732: Bugs: Need to protect calls against C99 math macro expansion (closed: fixed)">#8732</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/8733" title="#8733: Feature Requests: Testing for unprotected references to C99 math macros (closed: fixed)">#8733</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/8837" title="#8837: Bugs: boost::math::students_t quantile() fails for huge degrees of freedom (closed: fixed)">#8837</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/8940" title="#8940: Bugs: Argument promotion fails dependent libs on platforms not supporting ... (closed: fixed)">#8940</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/9042" title="#9042: Bugs: boost::math, cdf(complement(normal_distribution&lt;&gt;(...)) fails to catch ... (closed: fixed)">#9042</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/9087" title="#9087: Support Requests: [boost math] error: no operator &#34;=&#34; matches these operands in ... (closed: fixed)">#9087</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/9104" title="#9104: Bugs: boost::math::ellint_2 bug in x86_64 double precision (closed: fixed)">#9104</a>, refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/9126" title="#9126: Bugs: Logistic distribution pdf() and cdf(complement()) fail to catch ... (closed: fixed)">#9126</a>. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>John Maddock</dc:creator> <pubDate>Sun, 22 Dec 2013 17:05:45 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/9126#comment:9 https://svn.boost.org/trac10/ticket/9126#comment:9 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> Ticket