boostorg / multiprecision

Boost.Multiprecision
Boost Software License 1.0
198 stars 112 forks source link

complex number type #41

Closed jtravs closed 6 years ago

jtravs commented 6 years ago

Is there any work or reference for a complex number type based on a gmp_float or mpfr_float? I believe that I cannot just use e.g. g++ or clang std::complex<T>.

jzmaddock commented 6 years ago

Someone had a student working on it, I've just pinged them.

ckormanyos commented 6 years ago

There was another person interested in this a few years ago. I think might even be on the review schedule (or was on it fow a while a few years ago). But no one is driving it forward. Recently, the student that John mentioned has also worked in this area. I have an implementation that I would be happy to share if there is any interest in comparing notes. Although std::complex is only specified for instantiation with float, double and long double, there is a chance that it might (in a non-specified way) work with UDTs.

ckormanyos commented 6 years ago

Here it is if anyone would like to take a look. This code has been extensively tested with built-in float, double and long double. It has also been tested with Boost.Multiprecision types and with a variety of fixed-point types on target systems ranging from 8-bit, 16-bit, 32-bit, 64-bit. https://github.com/ckormanyos/real-time-cpp/blob/master/ref_app/src/math/extended_complex/extended_complex.h

ckormanyos commented 6 years ago

The link was broken. It is here. [https://github.com/ckormanyos/real-time-cpp/blob/master/ref_app/src/math/extended_complex/extended_complex.h]

jtravs commented 6 years ago

Thank you for sharing this. I will test it myself.

mglisse commented 6 years ago

Looking at https://gcc.gnu.org/ml/gcc-patches/2014-02/msg01377.html and the SO post referenced there, it seems that std::complex+Boost.Multiprecision worked at some point with libstdc++ (gcc), though it didn't work with libc++ (llvm). I don't know what the current status is. Writing a backend based on MPC should be better than using mpfr_float, but that's likely more work, especially if one wants optimized interaction with mpfr_float.

jzmaddock commented 6 years ago

There's never been any guarantee that std::complex will work with anything except float, double and long double unfortunately. Writing a backend based on MPC looks reasonable straightforward actually, there would be a lot of details to figure out though I'm sure.

ofloveandhate commented 6 years ago

indeed, as John says, std::complex with things other than float, double and long double can be made to "work" (compile) but some functions like arg produce low-precision numbers no matter the precision of the scalar type, so the results are not reliable.

ofloveandhate commented 6 years ago

i have prepared and attached a test file to contribute to the mpc effort. i am sure there are holes in my tests (i welcome criticism!), and they perhaps test things other don't care about such as

but I really want those features, so left them in.

complex_test.cpp.zip

thanks! ~Danielle

mglisse commented 6 years ago

but some functions like arg produce low-precision numbers no matter the precision of the scalar type

Do they? As I understand the libstdc++ code for arg, it calls atan2, and if you have an overload of atan2 for your multiprecision type, it uses it. (I know that's not portable to other implementations, I am only talking about libstdc++)

ofloveandhate commented 6 years ago

i have had problems with it personally... essentially getting a double precision result from my high-precision scalar type (mpfr_float with variable precision), so something in the middle got de-rezzed <word choice?>. maybe i was doing something wrong, and that experience was several years ago. if you are really interested in the failing test case, i can dig it up.

jzmaddock commented 6 years ago

In case anyone would like to give it a try... the branch "complex" has hopefully now complete support for complex numbers via mpc, see https://github.com/boostorg/multiprecision/tree/complex.

The usual typedefs are:

using boost::multiprecision::backends::mpc_complex_backend;

typedef number<mpc_complex_backend<50> >    mpc_complex_50;
typedef number<mpc_complex_backend<100> >   mpc_complex_100;
typedef number<mpc_complex_backend<500> >   mpc_complex_500;
typedef number<mpc_complex_backend<1000> >  mpc_complex_1000;
typedef number<mpc_complex_backend<0> >     mpc_complex;
ofloveandhate commented 6 years ago

i have boost 1.65 & 1.66 installed from homebrew on my machine i am testing with, and i am getting an include error when trying to use my clone of this repo (on complex branch):

In file included from src/basics/mpfr_extensions.cpp:33:
In file included from ./include/bertini2/mpfr_extensions.hpp:38:
In file included from /Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/mpfr.hpp:9:
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:25:10: fatal error: 
      'boost/container_hash/hash.hpp' file not found
#include <boost/container_hash/hash.hpp>
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

poking around in my installed boost, i do not have boost/container_hash.

jzmaddock commented 6 years ago

poking around in my installed boost, i do not have boost/container_hash.

Darn, it's been moved in current Boost develop, you can grab a copy from https://github.com/boostorg/container_hash

ofloveandhate commented 6 years ago

thanks, got it off the ground now.

ofloveandhate commented 6 years ago

i think i got my first error that wasn't my fault:

./include/bertini2/eigen_extensions.hpp:168:13: error: no matching constructor for initialization of 'Scalar' (aka
      'number<mpc_complex_backend<0>, bmp::et_on>')
  ...Scalar(numext::real(x)*numext::real(y) + numext::imag(x)*numext::imag(y), numext::imag(x)*numext::real(y) - numext::real(x)*numext::imag(y)...
     ^      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:83:50: note: 
      candidate constructor [with V = boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>] not viable: no known conversion from
      'detail::expression<detail::minus, detail::expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, detail::expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void> >' to
      'typename boost::enable_if_c<detail::is_explicitly_convertible<typename detail::canonical<expression<plus,
      expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void>, void,
      void>, mpc_complex_backend<0> >::type, mpc_complex_backend<0> >::value && (detail::is_restricted_conversion<typename
      detail::canonical<expression<plus, expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void>, void,
      void>, mpc_complex_backend<0> >::type, mpc_complex_backend<0> >::value || !is_convertible<typename
      detail::canonical<expression<plus, expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void>, void,
      void>, mpc_complex_backend<0> >::type, mpc_complex_backend<0> >::value)>::type *' (aka 'void *') for 2nd argument
   explicit BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c<
                                                 ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:193:4: note: 
      candidate constructor [with tag = boost::multiprecision::detail::plus, Arg1 =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, Arg2 =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, Arg3 = void, Arg4 = void] not viable: no known conversion
      from 'detail::expression<detail::minus, detail::expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, detail::expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void> >' to
      'typename boost::enable_if_c<is_convertible<typename detail::expression<plus, expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void>,
      expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>::result_type, self_type>::value>::type *'
      (aka 'void *') for 2nd argument
   number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, typename boost::enable_if_c<is_convertible<typename detail::...
   ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:69:41: note: 
      candidate constructor not viable: no known conversion from 'detail::expression<detail::minus,
      detail::expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, detail::expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void> >' to
      'unsigned int' for 2nd argument
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e, unsigned digits10) 
                                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:131:25: note: 
      candidate template ignored: deduced conflicting types for parameter 'V' ('expression<boost::multiprecision::detail::plus,
      [4 * ...]>' vs. 'expression<boost::multiprecision::detail::minus, [4 * ...]>')
   BOOST_MP_FORCEINLINE number(V v1, V v2, typename boost::enable_if<mpl::or_<boost::is_arithmetic<V>, is_same<std::string, V>, ...
                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:49:25: note: 
      candidate template ignored: substitution failure [with V =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>]: no type named 'type' in
      'boost::enable_if_c<false, void>'
   BOOST_MP_FORCEINLINE number(const V& v, typename boost::enable_if_c<
                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:61:41: note: 
      candidate template ignored: substitution failure [with V =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>]: no type named 'type' in
      'boost::enable_if_c<false, void>'
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c<
                                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:73:34: note: 
      candidate template ignored: substitution failure [with V =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>]: no type named 'type' in
      'boost::enable_if_c<false, void>'
   explicit BOOST_MP_FORCEINLINE number(const V& v, typename boost::enable_if_c<
                                 ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:107:25: note: 
      candidate template ignored: could not match 'number' against 'expression'
   BOOST_MP_FORCEINLINE number(const number<Other, ET>& val,
                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:113:13: note: 
      candidate template ignored: could not match 'number' against 'expression'
   explicit number(const number<Other, ET>& val, typename boost::enable_if_c<
            ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:124:34: note: 
      candidate template ignored: could not match 'number' against 'expression'
   explicit BOOST_MP_FORCEINLINE number(const number<Other, ET>& val, typename boost::enable_if_c<
                                 ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:137:25: note: 
      candidate template ignored: could not match 'number' against 'expression'
   BOOST_MP_FORCEINLINE number(const number<Other, ET>& v1, const number<Other, ET>& v2, typename boost::enable_if<boost::is_con...
                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:198:13: note: 
      candidate template ignored: substitution failure [with tag = boost::multiprecision::detail::plus, Arg1 =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, Arg2 =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, Arg3 = void, Arg4 = void]: no type named 'type' in
      'boost::enable_if_c<false, void>'
   explicit number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e,
            ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:103:41: note: 
      candidate constructor template not viable: requires single argument 'val', but 2 arguments were provided
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number<Backend, ET>& val)
                                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:47:41: note: 
      candidate constructor not viable: requires single argument 'e', but 2 arguments were provided
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e) BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Backend const...
                                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:206:41: note: 
      candidate constructor not viable: requires single argument 'r', but 2 arguments were provided
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(number&& r)
                                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:46:41: note: 
      candidate constructor not viable: requires 0 arguments, but 2 were provided
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number() BOOST_MP_NOEXCEPT_IF(noexcept(Backend())) {}
                                        ^

that is, is there a complex constructor that takes two real expressions? or, is it the case that the real() and imag() getters are returning complexes instead of reals?

based on this:

typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
      real()const
   {
      typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type result;
      eval_real(result.backend(), backend());
      return result;
   }

it appears that real() and imag() give complex, not real values.

ofloveandhate commented 6 years ago

the numext::real(...) function is defined in my version of Eigen (3.3.4 from homebrew) in MathFunctions.h at line 873 thusly:

template<typename Scalar>
EIGEN_DEVICE_FUNC
inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x)
{
  return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x);
}

that is, i believe that Eigen is not mangling the reality of the number it is returning (though i don't know whether it is returning a copy, possibly causing precision confusion -- there is a different function for returning by ref). i haven't caught a real-complex mismatch in eigen for a while. keeping an open mind about their absence of real-complex bugs -- it has been a while since i caught one.

ofloveandhate commented 6 years ago

tangentially, i also want to ensure that the real and imag getters return a const-reference, not a copy, so that if the current default precision differs from that of the number, it returns the actual value, not a copy of questionable precision. looking at number.hpp:713, i don't know. i guess it is an expression, not a value, being returned from real, right?

jzmaddock commented 6 years ago

Do you have a simple example I can try and compile? Note that I've done nothing to support Eigen interoperability so far, and I'm pretty sure that the default version of Eigen::NumTraits will not be correct.

To answer some specific questions:

1) The return values from real and imag are scalar types (mpfr_float) not complex ones. 2) The values are returned by value not const-ref - there's no means of returning a const ref since we store an mpc_t and not a pair of mpfr_float's. I need to double check that copying mpfr/mpc types results in precision preservation (irrespective of whatever the default is), but they certainly should do so...

ofloveandhate commented 6 years ago

it'll take me a bit to make a minimal example. thanks for your reply.

jzmaddock commented 6 years ago

Any complex number examples in the Eigen docs?

ofloveandhate commented 6 years ago

yes, there are some, for example, for doing a complex Schur decomposition:

http://eigen.tuxfamily.org/dox/classEigen_1_1ComplexSchur.html

however, as you say, there are some things needed to make custom types usable with eigen -- i am checking if i can just drop in mpc to my current extensions that allowed my custom multiprecision complex to be used in Eigen. the error above was the first "no" answer i ran into.

that is, i don't see any examples straight away that we could use. the schur example requires random number generation to be defined with the custom type.

my current NumTraits that work for my custom complex are at https://github.com/bertiniteam/b2/blob/develop/core/include/bertini2/eigen_extensions.hpp

ofloveandhate commented 6 years ago

one thing i just noticed is that in my code, i provide a NumTraits for expressions of numbers:

    template<typename Expr1,typename Expr2, typename Expr3>
    struct NumTraits<
        boost::multiprecision::detail::expression<Expr1,
        Expr2, Expr3, void, void>
            > : NumTraits<mpfr_real> // permits to get the epsilon, dummy_precision, lowest, highest functions
    {

        typedef mpfr_real Real;
        typedef mpfr_real NonInteger;
        typedef mpfr_real Nested;
    };

but it's only for reals. so, i at least need one for complexes. now, to make it co-vary with the scalar type...

ofloveandhate commented 6 years ago

is this the constructor you think should be used when constructing a complex from two expressions of reals?

template <class V>
   BOOST_MP_FORCEINLINE number(V v1, V v2, typename boost::enable_if<mpl::or_<boost::is_arithmetic<V>, is_same<std::string, V>, is_convertible<V, const char*> > >::type* = 0)
   {
      using default_ops::assign_components;
      assign_components(m_backend, canonical_value(v1), canonical_value(v2));
   }
jzmaddock commented 6 years ago

Yes that's the one.

Just started with the first Eigen examples, here's a first cut at the traits class, no doubt still needing refinement:

namespace Eigen
{
   template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
   struct NumTraits<boost::multiprecision::number<Backend, ExpressionTemplates> >
   {
      typedef boost::multiprecision::number<Backend, ExpressionTemplates> self_type;
      typedef typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type Real;
      typedef self_type NonInteger; // Not correct but we can't do much better??
      typedef double Literal;
      typedef self_type Nested;
      enum {
         IsComplex = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_complex,
         IsInteger = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer,
         ReadCost = 1,
         AddCost = 4,
         MulCost = 8,
         IsSigned = std::numeric_limits<self_type>::is_specialized ? std::numeric_limits<self_type>::is_signed : true,
         RequireInitialization = 1,
      };
      static Real epsilon() { return std::numeric_limits<Real>::epsilon(); }
      static Real dummy_precision() { return epsilon(); }
      static Real highest() { return (std::numeric_limits<Real>::max)(); }
      static Real lowest() { return (std::numeric_limits<Real>::min)(); }
      static int digits10() { return std::numeric_limits<Real>::digits10; }
   };
}
ofloveandhate commented 6 years ago

i feel like these are more correct, since the precision varies at runtime (possibly)

inline static Real highest() {
    return (mpfr_real(1) - epsilon()) * pow(mpfr_real(2),mpfr_get_emax()-1);
}

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

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

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

static inline int digits10()
{
    return default_precision();
}
ofloveandhate commented 6 years ago

is there a problem with that constructor in that it expects the same expression for each argument?

ofloveandhate commented 6 years ago

you may also need some of these for eigen interoperability:

namespace Eigen {
namespace internal {
template<>
struct abs2_impl<mpfr_complex>
{
    static inline mpfr_real run(const mpfr_complex& x)
    {
        return real(x)*real(x) + imag(x)*imag(x);
    }
};

template<> inline mpfr_complex random<mpfr_complex>()
{
    return bertini::multiprecision::rand();
}

template<> inline mpfr_complex random<mpfr_complex>(const mpfr_complex& a, const mpfr_complex& b)
{
    return a + (b-a) * random<mpfr_complex>();
}

template<>
struct conj_helper<mpfr_complex, mpfr_complex, false, true>
{
    typedef mpfr_complex Scalar;
    EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const
    { return c + pmul(x,y); }

    EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const
    { return Scalar(real(x)*real(y) + imag(x)*imag(y), imag(x)*real(y) - real(x)*imag(y)); }
};

template<>
struct conj_helper<mpfr_complex, mpfr_complex, true, false>
{
    typedef mpfr_complex Scalar;
    EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const
    { return c + pmul(x,y); }

    EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const
    { return Scalar(real(x)*real(y) + imag(x)*imag(y), real(x)*imag(y) - imag(x)*real(y)); }
};

// see https://forum.kde.org/viewtopic.php?f=74&t=111176

// specializations to allow mixed arithmetic in Eigen
//int
template<>
struct scalar_product_traits<int,mpfr_complex>
{
    enum { Defined = 1 };
    typedef mpfr_complex ReturnType;
};

template<>
struct scalar_product_traits<mpfr_complex, int>
{
    enum { Defined = 1 };
    typedef mpfr_complex ReturnType;
};

//long
template<>
struct scalar_product_traits<long,mpfr_complex>
{
    enum { Defined = 1 };
    typedef mpfr_complex ReturnType;
};

template<>
struct scalar_product_traits<mpfr_complex, long>
{
    enum { Defined = 1 };
    typedef mpfr_complex ReturnType;
};

//long long
template<>
struct scalar_product_traits<long long,mpfr_complex>
{
    enum { Defined = 1 };
    typedef mpfr_complex ReturnType;
};

template<>
struct scalar_product_traits<mpfr_complex, long long>
{
    enum { Defined = 1 };
    typedef mpfr_complex ReturnType;
};

//mpfr_real
template<>
struct scalar_product_traits<mpfr_real,mpfr_complex>
{
    enum { Defined = 1 };
    typedef mpfr_complex ReturnType;
};

template<>
struct scalar_product_traits<mpfr_complex, mpfr_real>
{
    enum { Defined = 1 };
    typedef mpfr_complex ReturnType;
};

//mpz_int
template<>
struct scalar_product_traits<mpz_int,mpfr_complex>
{
    enum { Defined = 1 };
    typedef mpfr_complex ReturnType;
};

template<>
struct scalar_product_traits<mpfr_complex, mpz_int>
{
    enum { Defined = 1 };
    typedef mpfr_complex ReturnType;
};

} // re: namespace internal
} // re: namespace Eigen

where going down the random number generation part opens yet another can of worms.

ofloveandhate commented 6 years ago

i was just playing around with the error messages, and added two bits of code to the system in an effort to get past this error.

1 -- number.hpp

   template <class V, class W>
   BOOST_MP_FORCEINLINE number(V v1, W v2, 
      typename boost::enable_if<
                           mpl::and_<
                              mpl::or_<
                                 boost::is_arithmetic<V>, 
                                 is_same<std::string, V>, 
                                 is_convertible<V, const char*> 
                                 >,
                              mpl::or_<
                                 boost::is_arithmetic<W>, 
                                 is_same<std::string, W>, 
                                 is_convertible<W, const char*> 
                                 >
                              > // and_
                              >::type* = 0)
   {
      using default_ops::assign_components;
      assign_components(m_backend, canonical_value(v1), canonical_value(v2));
   }
  1. default_ops.hpp
template <class T, class V1, class V2> 
inline void assign_components(T& result, const V1& v1, const V2& v2)
{
   return assign_components_imp(result, v1, v2, typename number_category<T>::type());
}

at least gets past the conficting template type error coming from the singly-templated constructor i referred to above:

/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:131:25: note: 
      candidate template ignored: deduced conflicting types for parameter 'V' ('expression<boost::multiprecision::detail::plus,
      [4 * ...]>' vs. 'expression<boost::multiprecision::detail::minus, [4 * ...]>')
   BOOST_MP_FORCEINLINE number(V v1, V v2, typename boost::enable_if<mpl::or_<boost::is_arithmetic<V>, is_same<std::string, V>, ...

however, the compiler is claiming the two-parameter constructor i added was disabled:

/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:141:28: note: 
      candidate template ignored: disabled by 'enable_if' [with V =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>, W =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::minus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>]
                           mpl::and_<

relaxing the conditional, the or_ is failing for both V and W.

replacing my test constructor with

template <class V1, class V2>
   BOOST_MP_FORCEINLINE number(V1 v1, V2 v2, 
      typename boost::enable_if<
                           mpl::and_<
                              mpl::or_<
                                 boost::is_arithmetic<V1>, 
                                 is_number_expression<V1>, 
                                 is_same<std::string, V1>, 
                                 is_convertible<V1, const char*> 
                                 >,
                              mpl::or_<
                                 boost::is_arithmetic<V2>, 
                                 is_number_expression<V2>, 
                                 is_same<std::string, V2>, 
                                 is_convertible<V2, const char*> 
                                 >
                              >
                              >::type* = 0)
   {
      using default_ops::assign_components;
      assign_components(m_backend, canonical_value(v1), canonical_value(v2));
   }

eliminated the error and let me move on to other errors that are clearly my fault, though i am only through like 5% of the compile process. (i am trying to just use the new type in my project, not building up to it)

is it nonsense to use is_number_expression in this context?

ofloveandhate commented 6 years ago

may we also please have real(...) and imag(...) setters, in addition to getters?

./include/bertini2/function_tree/symbols/linear_product.hpp:105:36: error: too many arguments to function call, expected 0, have 1
                                                coeffs_mpfr_ref(ii,jj).real( static_cast<mpfr_float>(coeffs_rat_real_(ii,jj)) );
                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:739:4: note: 'real'
      declared here
   typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
   ^
In file included from src/function_tree/node.cpp:27:
In file included from ./include/bertini2/function_tree.hpp:42:
./include/bertini2/function_tree/symbols/linear_product.hpp:106:36: error: too many arguments to function call, expected 0, have 1
                                                coeffs_mpfr_ref(ii,jj).imag( static_cast<mpfr_float>(coeffs_rat_imag_(ii,jj)) );
                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:746:4: note: 'imag'
      declared here
   typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
   ^

i am still not 100% with the internal yoga for this implementation, so perhaps need a bit of coaching to implement them myself.

ofloveandhate commented 6 years ago

looks like i declared victory a bit early on the constructor i added. getting further in the compile process revealed this new error:

/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/detail/default_ops.hpp:836:11: error: 
      no matching function for call to 'assign_components_imp'
   return assign_components_imp(result, v1, v2, typename number_category<T>::type());
          ^~~~~~~~~~~~~~~~~~~~~
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:134:7: note: in
      instantiation of function template specialization
      'boost::multiprecision::default_ops::assign_components<boost::multiprecision::backends::mpc_complex_backend<0>, const char *>'
      requested here
      assign_components(m_backend, canonical_value(v1), canonical_value(v2));
      ^
./include/bertini2/num_traits.hpp:281:11: note: in instantiation of function template specialization
      'boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<0>,
      boost::multiprecision::expression_template_option::et_on>::number<std::__1::basic_string<char> >' requested here
                        return mpfr_complex(s,t);
                               ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/detail/default_ops.hpp:825:13: note: 
      candidate function not viable: no known conversion from 'int_<4>' to 'const int_<number_kind_rational aka 2>' for 4th
      argument
inline void assign_components_imp(T& result, const V& v1, const V& v2, const mpl::int_<number_kind_rational>&)
            ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/detail/default_ops.hpp:842:11: error: 
      no matching function for call to 'assign_components_imp'
   return assign_components_imp(result, v1, v2, typename number_category<T>::type());
          ^~~~~~~~~~~~~~~~~~~~~
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:158:7: note: in
      instantiation of function template specialization
      'boost::multiprecision::default_ops::assign_components<boost::multiprecision::backends::mpc_complex_backend<0>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::minus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void> >' requested here
      assign_components(m_backend, canonical_value(v1), canonical_value(v2));
      ^
./include/bertini2/eigen_extensions.hpp:168:13: note: in instantiation of function template specialization
      'boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<0>,
      boost::multiprecision::expression_template_option::et_on>::number<boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::minus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void> >' requested here
                        { return Scalar(real(x)*real(y) + imag(x)*imag(y), imag(x)*real(y) - real(x)*imag(y)); }
                                 ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/detail/default_ops.hpp:825:13: note: 
      candidate template ignored: deduced conflicting types for parameter 'V' ('expression<boost::multiprecision::detail::plus,
      [4 * ...]>' vs. 'expression<boost::multiprecision::detail::minus, [4 * ...]>')
inline void assign_components_imp(T& result, const V& v1, const V& v2, const mpl::int_<number_kind_rational>&)
            ^

the first error immediately above comes from the following code:

inline static 
        mpfr_complex FromString(std::string const& s, std::string const& t)
        {
            return mpfr_complex(s,t);
        }

in sum, i think we still need assign_components_imp for complex numbers, with expression and string inputs for the real and complex components.

jzmaddock commented 6 years ago

Hi Danielle, I'm a bit behind you on this - what I'm trying to do at present is work through the Eigen examples in the docs and gradually add everything that needs adding (mostly Eigen traits classes so far).

With regard to the 2-arg constructor, yes it should be possible to make it work with 2 different args and/or 2 args which are not the same as the component_type, but a 2-arg string constructor would be explicit just like the single argument one.

ofloveandhate commented 6 years ago

Thanks so much for your work on this!!!

I have a moderate amount of test code for Eigen compatibility that i'd like to share, to help speed your process. LU and SVD are notably tested (at least as far as compilability) in this code. eigen_test.cpp.zip

hope this helps. trying to get stuff like this done this week while on spring break!

jzmaddock commented 6 years ago

I've pushed a partial fix for the 2-arg constructor issue, also first cut at an Eigen test suite (at least one of the tests is generating garbage results though). See: https://github.com/boostorg/multiprecision/commit/1a32ade24c343a74d6faa27e23f81b8821e3aab2

ofloveandhate commented 6 years ago

still getting an error on the two-expression constructor:

./include/bertini2/eigen_extensions.hpp:168:13: error: no matching constructor for initialization of 'Scalar' (aka
      'number<mpc_complex_backend<0>, bmp::et_on>')
                        { return Scalar(real(x)*real(y) + imag(x)*imag(y), imag(x)*real(y) - real(x)*imag(y)); }
                                 ^      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:83:50: note: 
      candidate constructor [with V = boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>] not viable: no known conversion from
      'detail::expression<detail::minus, detail::expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, detail::expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void> >' to
      'typename boost::enable_if_c<detail::is_explicitly_convertible<typename detail::canonical<expression<plus,
      expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void>, void,
      void>, mpc_complex_backend<0> >::type, mpc_complex_backend<0> >::value && (detail::is_restricted_conversion<typename
      detail::canonical<expression<plus, expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void>, void,
      void>, mpc_complex_backend<0> >::type, mpc_complex_backend<0> >::value || !is_convertible<typename
      detail::canonical<expression<plus, expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void>, void,
      void>, mpc_complex_backend<0> >::type, mpc_complex_backend<0> >::value)>::type *' (aka 'void *') for 2nd argument
   explicit BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c<
                                                 ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:202:4: note: 
      candidate constructor [with tag = boost::multiprecision::detail::plus, Arg1 =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, Arg2 =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, Arg3 = void, Arg4 = void] not viable: no known conversion
      from 'detail::expression<detail::minus, detail::expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, detail::expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void> >' to
      'typename boost::enable_if_c<is_convertible<typename detail::expression<plus, expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void>,
      expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>::result_type, self_type>::value>::type *'
      (aka 'void *') for 2nd argument
   number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, typename boost::enable_if_c<is_convertible<typename detail::...
   ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:69:41: note: 
      candidate constructor not viable: no known conversion from 'detail::expression<detail::minus,
      detail::expression<multiply_immediates, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, number<mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, detail::expression<multiply_immediates,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>,
      number<mpfr_float_backend<0, allocate_dynamic>, boost::multiprecision::expression_template_option::et_on>, void, void> >' to
      'unsigned int' for 2nd argument
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e, unsigned digits10) 
                                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:49:25: note: 
      candidate template ignored: substitution failure [with V =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>]: no type named 'type' in
      'boost::enable_if_c<false, void>'
   BOOST_MP_FORCEINLINE number(const V& v, typename boost::enable_if_c<
                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:61:41: note: 
      candidate template ignored: substitution failure [with V =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>]: no type named 'type' in
      'boost::enable_if_c<false, void>'
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c<
                                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:73:34: note: 
      candidate template ignored: substitution failure [with V =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>]: no type named 'type' in
      'boost::enable_if_c<false, void>'
   explicit BOOST_MP_FORCEINLINE number(const V& v, typename boost::enable_if_c<
                                 ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:107:25: note: 
      candidate template ignored: could not match 'number' against 'expression'
   BOOST_MP_FORCEINLINE number(const number<Other, ET>& val,
                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:113:13: note: 
      candidate template ignored: could not match 'number' against 'expression'
   explicit number(const number<Other, ET>& val, typename boost::enable_if_c<
            ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:124:34: note: 
      candidate template ignored: could not match 'number' against 'expression'
   explicit BOOST_MP_FORCEINLINE number(const number<Other, ET>& val, typename boost::enable_if_c<
                                 ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:131:25: note: 
      candidate template ignored: substitution failure [with V =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>, U =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::minus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>]: no type named 'type' in
      'boost::enable_if_c<false, void>'
   BOOST_MP_FORCEINLINE number(const V& v1, const U& v2, 
                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:138:25: note: 
      candidate template ignored: substitution failure [with V =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>, U =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::minus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>]: no type named 'type' in
      'boost::enable_if_c<false, void>'
   BOOST_MP_FORCEINLINE number(const V& v1, const U& v2,
                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:146:25: note: 
      candidate template ignored: could not match 'number' against 'expression'
   BOOST_MP_FORCEINLINE number(const number<Other, ET>& v1, const number<Other, ET>& v2, typename boost::enable_if<boost::is_con...
                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:207:13: note: 
      candidate template ignored: substitution failure [with tag = boost::multiprecision::detail::plus, Arg1 =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, Arg2 =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, Arg3 = void, Arg4 = void]: no type named 'type' in
      'boost::enable_if_c<false, void>'
   explicit number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e,
            ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:103:41: note: 
      candidate constructor template not viable: requires single argument 'val', but 2 arguments were provided
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number<Backend, ET>& val)
                                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:47:41: note: 
      candidate constructor not viable: requires single argument 'e', but 2 arguments were provided
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e) BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Backend const...
                                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:215:41: note: 
      candidate constructor not viable: requires single argument 'r', but 2 arguments were provided
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(number&& r)
                                        ^
/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:46:41: note: 
      candidate constructor not viable: requires 0 arguments, but 2 were provided
   BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number() BOOST_MP_NOEXCEPT_IF(noexcept(Backend())) {}
                                        ^

where the one that i think is supposed to work is the constructor at number.hpp:131:

/Users/brakeda/math_projects/bertini2/boost_mp_complex/multiprecision_clone/include/boost/multiprecision/number.hpp:131:25: note: 
      candidate template ignored: substitution failure [with V =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::plus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>, U =
      boost::multiprecision::detail::expression<boost::multiprecision::detail::minus,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_immediates,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>,
      boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<0, allocate_dynamic>,
      boost::multiprecision::expression_template_option::et_on>, void, void>, void, void>]: no type named 'type' in
      'boost::enable_if_c<false, void>'
   BOOST_MP_FORCEINLINE number(const V& v1, const U& v2, 
                        ^

you may have already known that, since you indicated it is a partial fix.

what version of eigen are you testing against? i've been at 3.3.4 for a while, supplied by brew. happy to upgrade to match you. happy to stay where i am. i'll not go back to 3.2.x -- there are some bugs fixed going to 3.3.x.

jzmaddock commented 6 years ago

OK, latest code in the "complex" branch should have fixed those errors. I have most of the Eigen examples building, plus a modified version of your test suite (attached).

What isn't working, is scalar operations on related types:

my_matrix *= some_related_type;

where some_related_type is would normally interoperate with the the matrix's value_type: for example multiplying a matrix of mpfr_foat's by an mpz_int. The issue is that Eigen has it's own partial specialisation of ScalarBinaryOpTraits for complex types, and I've been unable to find other partial specializations that don't generate ambiguities with that. Well actually, I had it all working with msvc, but gcc and clang rejected the code :( Currently your mpz_int interoperability tests are commented out for that reason. Strangely msvc tries to instantiate ScalarBinaryOpTraits<mpz_int, float, Op> if you uncomment that code - and that static_asserts (with good reason). Even stranger, gcc does seem to accept the code, but it really shouldn't! eigen_test.zip

jzmaddock commented 6 years ago

I take back the comment on matrixes of mpc_complex not interoperating with mpz_int: they do, since the complex type is implicitly constructed from the mpz_int. I don't know why msvc triggers the static asserts, it's extremely annoying as it has no business instantiating those templates at all (and the instantiation backtrace is useless).

Eigen could actually be a bit more efficient in this context as it's creating a copy of the scalar multiplier rather than passing the actual type of the multiplier down to the inner loop. Not that it matters in this context...

ofloveandhate commented 6 years ago

see this so post for a question i asked related to *=

jzmaddock commented 6 years ago

see this so post for a question i asked related to *=

Actually I think it's all working with latest Eigen and the code I posted above, this all works OK:

      Eigen::Matrix<boost::multiprecision::mpc_complex, 3, 1> mat, mat2;
      mat << 1, 2, 3;
      mat *= 2;
      mat *= 3.0f;

      boost::multiprecision::mpc_complex com(2, 3);
      mat *= com;
      mat *= real(com);

      boost::multiprecision::mpz_int z(56);
      mat /= z;

      Eigen::Matrix<boost::multiprecision::cpp_bin_float_50, 4, 1> cpp_mat, cpp_mat2;
      cpp_mat *= 2;
      cpp_mat *= 3.0;
      boost::multiprecision::cpp_bin_float_quad q(2.0);
      cpp_mat *= q;

      mat2 = mat * 2;
      mat2 = 2 * mat;
      mat2 = mat * 3.0L;
      mat2 = 2.0 * mat;
      mat2 = mat * com;
      mat2 = com * mat;
      mat2 = real(com) * mat;
      mat2 = mat * real(com);
      mat2 = mat * z;
      mat2 = z * mat;

      cpp_mat2 = cpp_mat * 2;
      cpp_mat2 = 2 * cpp_mat;
      cpp_mat2 = cpp_mat * 2.0;
      cpp_mat2 = 2.0 * cpp_mat;
      cpp_mat2 = cpp_mat * q;
      cpp_mat2 = q * cpp_mat;
ofloveandhate commented 6 years ago

yep, things look good on the Eigen front!

ofloveandhate commented 6 years ago

next thing that keeps me from compiling is a real/imag pair of setters

jzmaddock commented 6 years ago

next thing that keeps me from compiling is a real/imag pair of setters

I'm conflicted about that: it's not part of the std::complex interface, and there's no way to set just one part of an mpc_t anyway. What's the use case?

mglisse commented 6 years ago

there's no way to set just one part of an mpc_t anyway

mpc_realref and mpc_imagref?

jzmaddock commented 6 years ago

mpc_realref and mpc_imagref?

You got me there! :)

Good catch.

jzmaddock commented 6 years ago

Getters and setters for real/imag now added: I'm hoping that's the coding done now, give or take...

ofloveandhate commented 6 years ago

i got much further. here's my first test that failed:

test case:

auto exact_mpfr = pow(sqrt(xnum_mpc),anum_mpc);
somethingsomething exact_mpfr.imag();

with error:

test/classes/function_tree_test.cpp:1301:55: error: no member named 'real' in 'boost::multiprecision::detail::expression<boost::multiprecision::detail::function,
      boost::multiprecision::detail::number_kind_complexpow_funct<boost::multiprecision::backends::mpc_complex_backend<0> >,
      boost::multiprecision::detail::expression<boost::multiprecision::detail::function,
      boost::multiprecision::detail::number_kind_complexsqrt_funct<boost::multiprecision::backends::mpc_complex_backend<0> >,
      boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<0>, boost::multiprecision::expression_template_option::et_on>, void, void>,
      boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<0>, boost::multiprecision::expression_template_option::et_on>, void>'
        BOOST_CHECK(fabs(N->Eval<mpfr>().real() - exact_mpfr.real() ) < threshold_clearance_mp);

is this forbidden, and the result of an incorrect use of auto with ET-types running around? should expressions of complexes have an imag getter?

jzmaddock commented 6 years ago

is this forbidden, and the result of an incorrect use of auto with ET-types running around? should expressions of complexes have an imag getter?

I think I'm going to say "don't do that".

We do allow:

real(come-complex-expression)

However, the danger with allowing the member function is that you inadvertently write:

auto x = some-complex-expression;
auto r = x.real();
auto i = x.imag();  // Oops, "some-complex-expression" just got evaluated twice!

I might be able to improve the error messages somewhat though...

ofloveandhate commented 6 years ago

gotcha. thanks. almost done with the compiling stage for my first test executable for bertini2.

next question is about isnan and isinf functions. would you be into providing a pair of them? here's my probably janky implementation so i could get further:

    inline 
    bool isnan(mpfr_complex const& num)
    {
        using boost::math::isnan;
        if (isnan(num.real()) || isnan(num.imag()))
            return true;
        else
            return false;
    }

after this, it appears i have a few linker errors for undefined symbols, that will have to wait for a bit so i can catch up on some grading on which i am badly behind... here's a preview:

Undefined symbols for architecture x86_64:
  "_mpc_acos", referenced from:
      boost::multiprecision::detail::number_kind_complexacos_funct<boost::multiprecision::backends::mpc_complex_backend<0u> >::operator()(boost::multiprecision::backends::mpc_complex_backend<0u>&, boost::multiprecision::backends::mpc_complex_backend<0u> const&) const in b2_class_test-function_tree_test.o
      boost::multiprecision::detail::number_kind_complexacos_funct<boost::multiprecision::backends::mpc_complex_backend<0u> >::operator()(boost::multiprecision::backends::mpc_complex_backend<0u>&, boost::multiprecision::backends::mpc_complex_backend<0u> const&) const in b2_class_test-complex_test.o
  "_mpc_acosh", referenced from:
      boost::multiprecision::detail::number_kind_complexacosh_funct<boost::multiprecision::backends::mpc_complex_backend<0u> >::operator()(boost::multiprecision::backends::mpc_complex_backend<0u>&, boost::multiprecision::backends::mpc_complex_backend<0u> const&) const in b2_class_test-complex_test.o
  "_mpc_add", referenced from:
      void boost::multiprecision::backends::eval_add<0u, 0u, 0u>(boost::multiprecision::backends::mpc_complex_backend<0u>&, boost::multiprecision::backends::mpc_complex_backend<0u> const&, boost::multiprecision::backends::mpc_complex_backend<0u> const&) in b2_class_test-eigen_test.o

i think i need to link to mpc, wherever that is coming from.

ofloveandhate commented 6 years ago

got it, of course i have to link with mpc.

ckormanyos commented 6 years ago

i think i need to link to mpc, wherever that is coming from. Probably. But this might involve a few more steps.

MPC means "Multiple Precision Complex". It is a library that abstractscomplex multiple precision numbers on top of several layers of additionalsoftware. If I recall, then MPC is based on MPFR, which is subsequently basedon GMP. So in fact, you might need all of these libraries in order tosuccessfully link the project. GMP provides real-valued multiple precicision numbers, but with justa few functions. MPFR adds additional precise rounging modes andeven more elementary functions on top of GMP. MPC wraps MPFRand provides the complex number type. Depending on your system, you can select (for the low-level real type)either GMP or MPIR. I have only followed your work indirectly, but it seems like you mightbe wrapping MPC in yet another layer that allows this complex typein Boost.Multiprecision so that it behaves very much like an STLcomplex type, but can be instantiated for user-defined types. During the early work of Boost.Multiprecision, John ensured thatthese types were properly wrapped as back end number typesso that the so-called "number" layer could be instantiated withGMP or MPFR types. With kind regards, Chris

On Friday, April 6, 2018, 12:45:50 AM GMT+2, danielle brake <notifications@github.com> wrote:  

gotcha. thanks. almost done with the compiling stage for my first test executable for bertini2.

next question is about isnan and isinf functions. would you be into providing a pair of them? here's my probably janky implementation so i could get further: inline bool isnan(mpfr_complex const& num) { using boost::math::isnan; if (isnan(num.real()) || isnan(num.imag())) return true; else return false; }

after this, it appears i have a few linker errors for undefined symbols, that will have to wait for a bit so i can catch up on some grading on which i am badly behind... here's a preview: Undefined symbols for architecture x86_64: "_mpc_acos", referenced from: boost::multiprecision::detail::number_kind_complexacos_funct<boost::multiprecision::backends::mpc_complex_backend<0u> >::operator()(boost::multiprecision::backends::mpc_complex_backend<0u>&, boost::multiprecision::backends::mpc_complex_backend<0u> const&) const in b2_class_test-function_tree_test.o boost::multiprecision::detail::number_kind_complexacos_funct<boost::multiprecision::backends::mpc_complex_backend<0u> >::operator()(boost::multiprecision::backends::mpc_complex_backend<0u>&, boost::multiprecision::backends::mpc_complex_backend<0u> const&) const in b2_class_test-complex_test.o "_mpc_acosh", referenced from: boost::multiprecision::detail::number_kind_complexacosh_funct<boost::multiprecision::backends::mpc_complex_backend<0u> >::operator()(boost::multiprecision::backends::mpc_complex_backend<0u>&, boost::multiprecision::backends::mpc_complex_backend<0u> const&) const in b2_class_test-complex_test.o "_mpc_add", referenced from: void boost::multiprecision::backends::eval_add<0u, 0u, 0u>(boost::multiprecision::backends::mpc_complex_backend<0u>&, boost::multiprecision::backends::mpc_complex_backend<0u> const&, boost::multiprecision::backends::mpc_complex_backend<0u> const&) in b2_class_test-eigen_test.o

i think i need to link to mpc, wherever that is coming from.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.