Re: [Boost-bugs] [Boost C++ Libraries] #11149: boost::multiprecision compilation fail with std::max

Subject: Re: [Boost-bugs] [Boost C++ Libraries] #11149: boost::multiprecision compilation fail with std::max
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2016-02-17 20:29:07


#11149: boost::multiprecision compilation fail with std::max
-------------------------------+----------------------------
  Reporter: minorlogic@… | Owner: johnmaddock
      Type: Bugs | Status: closed
 Milestone: To Be Determined | Component: multiprecision
   Version: Boost 1.57.0 | Severity: Showstopper
Resolution: wontfix | Keywords:
-------------------------------+----------------------------

Comment (by dbrake@…):

 thanks very much for continuing to troubleshoot this with me!

 i had to change the third and sixth templates, replacing `number<Backend,
 et_on>` with `typename detail::expression<tag, A1, A2, A3,
 A4>::result_type`.

 without the
 {{{
 namespace std{ using boost::multiprecision::min; using
 boost::multiprecision::max;
 }}}
 i still get `error: no matching function for call to 'max'`.

 with it, `error: call to 'max' is ambiguous`.

 {{{
 /usr/local/Cellar/eigen/3.2.7/include/eigen3/Eigen/src/SVD/JacobiSVD.h:876:66:
 error: call to 'max' is ambiguous
         RealScalar threshold = (max)(considerAsZero, precision *
 (max)(abs(m_workMatrix.coeff(p,p)),
                                                                  ^~~~~
 /usr/local/Cellar/eigen/3.2.7/include/eigen3/Eigen/src/SVD/JacobiSVD.h:578:7:
 note: in instantiation of member function
 'Eigen::JacobiSVD<Eigen::Matrix<boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0,
 allocate_dynamic>,
       boost::multiprecision::expression_template_option::et_on>, -1, -1,
 0, -1, -1>, 2>::compute' requested here
       compute(matrix, computationOptions);
       ^
 mwe_eigen_mpfr_max.cpp:161:78: note: in instantiation of member function
 'Eigen::JacobiSVD<Eigen::Matrix<boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0,
 allocate_dynamic>,
       boost::multiprecision::expression_template_option::et_on>, -1, -1,
 0, -1, -1>, 2>::JacobiSVD' requested here
         Eigen::JacobiSVD<Eigen::Matrix<mpfr_float, Eigen::Dynamic,
 Eigen::Dynamic>> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
 ^
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:2662:1:
 note: candidate function [with
       _Tp =
 boost::multiprecision::detail::expression<boost::multiprecision::detail::function,
 boost::multiprecision::detail::abs_funct<boost::multiprecision::backends::mpfr_float_backend<0,
 allocate_dynamic> >,
 boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0,
 allocate_dynamic>,
       boost::multiprecision::expression_template_option::et_on>, void,
 void>]
 max(const _Tp& __a, const _Tp& __b)
 ^
 mwe_eigen_mpfr_max.cpp:89:2: note: candidate function [with tag =
 boost::multiprecision::detail::function, A1 =
 boost::multiprecision::detail::abs_funct<boost::multiprecision::backends::mpfr_float_backend<0,
 allocate_dynamic> >, A2 =
 boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0,
 allocate_dynamic>,
       boost::multiprecision::expression_template_option::et_on>, A3 =
 void, A4 = void, tagb = boost::multiprecision::detail::function, A1b =
 boost::multiprecision::detail::abs_funct<boost::multiprecision::backends::mpfr_float_backend<0,
 allocate_dynamic> >, A2b =
 boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0,
 allocate_dynamic>,
       boost::multiprecision::expression_template_option::et_on>, A3b =
 void, A4b = void]
  max(const detail::expression<tag, A1, A2, A3, A4>& arg, const
  ^

 }}}

 the code i tested is below for reference.

 {{{
 #include <algorithm>
 #include <cmath>
 #include <boost/multiprecision/mpfr.hpp>

 using mpfr_float =
 boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0>,
 boost::multiprecision::et_on>;
 // changing et_on to et_off allows this code to compile.
 // the problem with min/max is with expression templates.

 namespace boost { namespace multiprecision {
 template <class Backend, class tag, class A1, class A2, class A3, class
  A4>
  inline number<Backend, et_on> min(const number<Backend, et_on>& a, const
  detail::expression<tag, A1, A2, A3, A4>& b)
  {
     number<Backend, et_on> t(b);
     if(a < t)
        return a;
     return BOOST_MP_MOVE(t);
  }
  template <class tag, class A1, class A2, class A3, class A4, class
  Backend>
  inline number<Backend, et_on> min(const detail::expression<tag, A1, A2,
  A3, A4>& a, const number<Backend, et_on>& b)
  {
     number<Backend, et_on> t(a);
     if(t < b)
        return BOOST_MP_MOVE(t);
     return b;
  }
  template <class tag, class A1, class A2, class A3, class A4, class tagb,
  class A1b, class A2b, class A3b, class A4b>
  inline typename detail::expression<tag, A1, A2, A3, A4>::result_type
  min(const detail::expression<tag, A1, A2, A3, A4>& arg, const
  detail::expression<tagb, A1b, A2b, A3b, A4b>& a)
  {
     // number<Backend, et_on> t1(a), t2(b);
     typename detail::expression<tag, A1, A2, A3, A4>::result_type t1(arg),
 t2(a);
     if(t1 < t2)
        return BOOST_MP_MOVE(t1);
     return BOOST_MP_MOVE(t2);
  }

  template <class Backend, class tag, class A1, class A2, class A3, class
  A4>
  inline number<Backend, et_on> max(const number<Backend, et_on>& a, const
  detail::expression<tag, A1, A2, A3, A4>& b)
  {
     number<Backend, et_on> t(b);
     if(a > t)
        return a;
     return BOOST_MP_MOVE(t);
  }
  template <class tag, class A1, class A2, class A3, class A4, class
  Backend>
  inline number<Backend, et_on> max(const detail::expression<tag, A1, A2,
  A3, A4>& a, const number<Backend, et_on>& b)
  {
     number<Backend, et_on> t(a);
     if(t > b)
        return BOOST_MP_MOVE(t);
     return b;
  }
  template <class tag, class A1, class A2, class A3, class A4, class tagb,
  class A1b, class A2b, class A3b, class A4b>
  inline typename detail::expression<tag, A1, A2, A3, A4>::result_type
  max(const detail::expression<tag, A1, A2, A3, A4>& arg, const
  detail::expression<tagb, A1b, A2b, A3b, A4b>& a)
  {
     // number<Backend, et_on> t1(a), t2(b);
     typename detail::expression<tag, A1, A2, A3, A4>::result_type t1(arg),
 t2(a);
     if(t1 > t2)
        return BOOST_MP_MOVE(t1);
     return BOOST_MP_MOVE(t2);
  }
  }}

  namespace std{ using boost::multiprecision::min; using
  boost::multiprecision::max;
 }

 // include AFTER the above templates
 #include <Eigen/Dense>

 // reopen the Eigen namespace to provide NumTraits for mpfr_float.
 namespace Eigen {
         // describe mpfr_float to Eigen
         // permits to get the epsilon, dummy_precision, lowest, highest
 functions
         template<> struct NumTraits<mpfr_float> :
 GenericNumTraits<mpfr_float>
         {

                 typedef mpfr_float Real;
                 typedef mpfr_float NonInteger;
                 typedef mpfr_float Nested;
                 enum {
                         IsComplex = 0,
                         IsInteger = 0,
                         IsSigned = 1,
                         RequireInitialization = 1, // yes, require
 initialization, otherwise get crashes
                         ReadCost = 20,
                         AddCost = 30,
                         MulCost = 40
                 };


                 inline static Real highest() {

                         return (mpfr_float(1) - epsilon()) *
 pow(mpfr_float(2),mpfr_get_emax()-1);
                 }

                 inline static Real lowest() {
                         return -highest();
                 }

                 inline static Real dummy_precision()
                 {
                         return pow(
 mpfr_float(10),-int(mpfr_float::default_precision()-3));
                 }

                 inline static Real epsilon()
                 {
                         return
 pow(mpfr_float(10),-int(mpfr_float::default_precision()));
                 }
         };

 }

 #include <iostream> // so i can print the V result of the SVD. not
 strictly necessary for this MWE

 int main()
 {
         // make a 2x2 dynamic matrix
         Eigen::Matrix<mpfr_float, Eigen::Dynamic, Eigen::Dynamic> A(2,2);
         A << 2, 1, 1, 2; // populate it


         // this is the offending line. Eigen attempts to call max, but
 cannot see the above templates, or has ambiguous call to max, depending on
 the presence of the using directives in namespace std.
         Eigen::JacobiSVD<Eigen::Matrix<mpfr_float, Eigen::Dynamic,
 Eigen::Dynamic>> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);

         std::cout << svd.matrixV();
         return 0;

 }
 }}}

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/11149#comment:17>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:19 UTC