Help testing release candidate for std::complex

One of the (best) features of ADL is that it will match templates not just from the concrete types that exist in the argument list, but also from the template types. Thus, if you write a generic function template like template<class T, class U, std::enable_if<yada yada yada>* =nullptr> stan::math::pow(std::complex<T>, U)… It will never appear in the overload set unless either T or U (or subtype of T or U) is in the stan math namespace. That’s how you can write your functions in prim and is what my linked implementation example does above. No overloading std::pow required. Also eliminates duplicate code & could be used in other situations to the same effect.

1 Like

There is also another degree of freedom / insertion seam, which could be combined with or used in lieu of ADL on T and U (in my implementation, it is combined). Essentially, the stan complex base type can be defined in prim. ADL pulls in namespaces of base classes. This is harder to use though.

I should also specify two caveats: No matter what happens, there will likely be secenarios requiring an overload of a function that is defined in std, either because the function is called explicitly with the std namespace prefix (like g++, implementation example here), or because after the promotions defined inside, let’s say, template functions in prim (note link is to the forwarding function call line number this time), the resulting forwarding function call becomes an exact match for a template function defined by <complex> in std::. In either of those two cases, at the rev or fwd level, the appropriate std overload must exist, though it can be much more narrow than before, since it doesn’t need to handle all the different promotions that the generic template in prim would need to do. You may also be able to sidestep the g++ std:: prefix situation, since you use your own implementations on stan types, but the 2nd situation probably still remains.

Anyway, sorry for rambling.

1 Like

That’s neat—I hadn’t realized it’d look at the instantiations when considering ADL, but of course that makes sense now that I think about it given the general way that templates work. I’ll start by seeing if I can replace all the overloads I made for pow with the three basic ones. It’d be nice to eliminate something like 18 of the definitions I have now.

OK—I think I have the appropriate specializations. I also have overloads defined in stan::math, which should take precedence over the std:: templates because they have more specific types. Either way, it should be OK. The libraries in clang++ and g++ are a mess around complex in that there are specializations in the spec admitted by one and not the other and vice-versa. I didn’t want to go down an ifdef route for that, so I just stuck to ones allowed by both.

I really appreciate the detailed tips and explanations. It’s really helpful not just for this case but for my general understanding of templates. I think I have enough testing in place I can start trying to simplify the implementations.

1 Like

You’re most welcome. It’s a pleasure to work with you. Especially considering that you’re adding code that will enable my workplace to transition off of my branch onto mainline stan-math. My colleagues (and I) are mechanical engineers. If I should leave, your implementation will help enable them contract out the maintenance of our commercial code to a 3rd party more easily. No one else where I work programs, and they don’t enjoy complex mathematics the same way, either. So, you’re really helping out!

1 Like

After git pull I’m now on commit b394c4215543151693b8d72d545caf0cc7c8e00b (HEAD -> feature/0123-complex-var, origin/feature/0123-complex-var).

g++ and clang++ are giving me error messages like:
../eigen-git-mirror\Eigen/src/Core/Product.h:29:116: fatal error: no type named 'ReturnType' in 'Eigen::ScalarBinaryOpTraits<std::complex<stan::math::var>, double, Eigen::internal::scalar_product_op<std::complex<stan::math::var>, double> >'

This is occurring on a line where a matrix containing complex<var> gets multipled by a matrix containing double.

To get this working so that complex<var> can interoperate with double, Eigen wants the return type ScalarBinaryOpTraits<T1,T2,BinaryOp>::ReturnType to be defined. It would be straightforward, except that we have to be careful to avoid the relevant cases where Eigen already has it defined. Namely, the ones already defined are when T1=T2, when T1=std::complex<T2>, or T2=std::complex<T1>. Here’s the way I did the ScalarBinaryOpTraits struct specialization in mine at the prim level. Some notes: is_arith_like<T>::value is a template that returns true for var, fvar, or for anything that gives true from std::is_arithmetic<T>::value. Meanwhile, rm_complex_t removes any complex wrappers that may exist, giving the underlying type, and rm_zeroing_t removes any zeroing wrappers, which doesn’t exist in your implementation. Lastly, it’s important that T1 and T2 appear at least once a deducible context (as opposed to inside enable_if, which is a non-deducible context), which I did by including their names in the 3rd template argument to the specialization, as OP<T1,T2>, which requires that OP be a template template parameter as shown in the implementation example (template <class T1, class T2, template <class, class> class OP>).

Thanks much for the detailed explanation. I had thought I’d tested all those instantiations, but again, I missed all the combinatorics of the double/var/complex in testing multiplication. I can add all the tests, but I can’t seem to get the code to compile and I’ve been at it for almost two hours.

The other alternative is just to properly overload operator* so all the implementations exist. Again, we’re going to need to do that for efficient multiplication if we ever want it, but I was hoping to avoid that ton of work in this implementation.

I first tried to just build up simple instantiations, and when that didn’t work, I modified @ChrisChiasson’s suggested code as follows.

namespace Eigen {

template <class T1, class T2, template <class, class> class OP>
struct ScalarBinaryOpTraits<
    T1,
    std::enable_if_t<
        (stan::is_complex<T1>::value || stan::is_arithmetic<T1>::value)
            && (stan::is_complex<T2>::value || stan::is_arithmetic<T2>::value)
            && !std::is_same<T1, T2>::value &&  // avoid Eigen's template
            ((stan::is_complex<T1>::value &&    // next boolean avoids Eigen
              !std::is_same<stan::rm_complex_t<T1>,
                            stan::rm_complex_t<T2>>::value)
             || (stan::is_complex<T2>::value &&  // next bool avoids Eigen
                 !std::is_same<stan::rm_complex_t<T1>,
                               stan::rm_complex_t<T2>>::value)),
        T2>,
    OP<T1, T2>> {
  typedef std::complex<typename stan::return_type<stan::rm_complex_t<T1>,
                                                  stan::rm_complex_t<T2>>::type>
      ReturnType;
};

} // namespace Eigen

and included the new traits metaprograms:

namespace stan {

template <typename T>
struct is_complex {
  enum { value = 0 };
};
template <typename T>
struct is_complex<std::complex<T>> {
  enum { value = 1 };
};

template <typename T>
struct is_arithmetic {
  enum { value = std::is_arithmetic<T>::value };
};
template <>
struct is_arithmetic<stan::math::var> {
  enum { value = 1 };
};
template <typename T>
struct is_arithmetic<stan::math::fvar<T>> {
  enum { value = 1 };
};

template <typename T>
struct rm_complex {
  typedef T type;
};
template <typename T>
struct rm_complex<std::complex<T>> {
  typedef T type;
};

template <typename T>
using rm_complex_t = typename rm_complex<T>::type;

}  // namespace stan

The test I’m trying to add to start is this:

TEST(mathMix, multiplicationPatterns) {
  Eigen::Matrix<cvar_t, -1, -1> x(2, 2);
  x << 1, 2, 3, 4;
  Eigen::Matrix<cdouble_t, -1, -1> y(2, 2);
  y << 5, 6, 7, 8;

  auto z = x * y;
  auto a = z(0);  // this is where it fails
  std::cout << a << std::endl;
}

But then I just get an error novel which has zero clues that are useful to me in debugging, so I’m stuck. Are there other traits metaprograms that need to be defined? Do I also need to define implementations? At this point, I’m not sure how to debug given that the errors don’t loo like they’re at all related to anything I’m doing:

make -j8 test/unit/math/rev/core/std_complex_test
clang++ -std=c++1y -Wno-unknown-warning-option -Wno-tautological-compare -Wno-sign-compare -D_REENTRANT       -I lib/tbb_2019_U8/include -O0  -I . -I lib/eigen_3.3.3 -I lib/boost_1.69.0 -I lib/sundials_4.1.0/include -I lib/gtest_1.8.1/include -I lib/gtest_1.8.1 -I lib/gtest_1.8.1/include -I lib/gtest_1.8.1      -DBOOST_DISABLE_ASSERTS        -c -o test/unit/math/rev/core/std_complex_test.o test/unit/math/rev/core/std_complex_test.cpp
In file included from test/unit/math/rev/core/std_complex_test.cpp:1:
In file included from ./test/unit/math/test_ad.hpp:5:
In file included from ./test/unit/math/is_finite.hpp:4:
In file included from ./stan/math.hpp:148:
In file included from ./stan/math/rev/mat.hpp:4:
In file included from ./stan/math/prim/mat/fun/Eigen.hpp:13:
In file included from lib/eigen_3.3.3/Eigen/Dense:1:
In file included from lib/eigen_3.3.3/Eigen/Core:470:
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:980:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A0, B_0, C0, T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralMatrixMatrix.h:194:11: note: in instantiation of member function
      'Eigen::internal::gebp_kernel<std::__1::complex<stan::math::var>, std::__1::complex<double>, long,
      Eigen::internal::blas_data_mapper<std::__1::complex<stan::math::var>, long, 0, 0>, 2, 4, false, false>::operator()' requested here
          gebp(res.getSubMapper(i2, j2), blockA, blockB, actual_mc, actual_kc, actual_nc, alpha);
          ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralMatrixMatrix.h:226:11: note: in instantiation of member function 'Eigen::internal::general_matrix_matrix_product<long,
      std::__1::complex<stan::math::var>, 0, false, std::__1::complex<double>, 0, false, 0>::run' requested here
    Gemm::run(rows, cols, m_lhs.cols(),
          ^
lib/eigen_3.3.3/Eigen/src/Core/products/Parallelizer.h:97:3: note: in instantiation of member function 'Eigen::internal::gemm_functor<std::__1::complex<stan::math::var>,
      long, Eigen::internal::general_matrix_matrix_product<long, std::__1::complex<stan::math::var>, 0, false, std::__1::complex<double>, 0, false, 0>,
      Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1>, Eigen::Matrix<std::__1::complex<double>, -1, -1, 0, -1, -1>,
      Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1>, Eigen::internal::gemm_blocking_space<0, std::__1::complex<stan::math::var>,
      std::__1::complex<double>, -1, -1, -1, 1, false> >::operator()' requested here
  func(0,rows, 0,cols);
  ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralMatrixMatrix.h:483:15: note: in instantiation of function template specialization 'Eigen::internal::parallelize_gemm<true,
      Eigen::internal::gemm_functor<std::__1::complex<stan::math::var>, long, Eigen::internal::general_matrix_matrix_product<long, std::__1::complex<stan::math::var>, 0,
      false, std::__1::complex<double>, 0, false, 0>, Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1>, Eigen::Matrix<std::__1::complex<double>, -1, -1,
      0, -1, -1>, Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1>, Eigen::internal::gemm_blocking_space<0, std::__1::complex<stan::math::var>,
      std::__1::complex<double>, -1, -1, -1, 1, false> >, long>' requested here
    internal::parallelize_gemm<(Dest::MaxRowsAtCompileTime>32 || Dest::MaxRowsAtCompileTime==Dynamic)>
              ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralMatrixMatrix.h:435:7: note: in instantiation of function template specialization
      'Eigen::internal::generic_product_impl<Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1>, Eigen::Matrix<std::__1::complex<double>, -1, -1, 0, -1,
      -1>, Eigen::DenseShape, Eigen::DenseShape, 8>::scaleAndAddTo<Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1> >' requested here
      scaleAndAddTo(dst, lhs, rhs, Scalar(1));
      ^
lib/eigen_3.3.3/Eigen/src/Core/ProductEvaluators.h:124:69: note: in instantiation of function template specialization
      'Eigen::internal::generic_product_impl<Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1>, Eigen::Matrix<std::__1::complex<double>, -1, -1, 0, -1,
      -1>, Eigen::DenseShape, Eigen::DenseShape, 8>::evalTo<Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1> >' requested here
    generic_product_impl<Lhs, Rhs, LhsShape, RhsShape, ProductTag>::evalTo(m_result, xpr.lhs(), xpr.rhs());
                                                                    ^
lib/eigen_3.3.3/Eigen/src/Core/ProductEvaluators.h:35:62: note: in instantiation of member function
      'Eigen::internal::product_evaluator<Eigen::Product<Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1>, Eigen::Matrix<std::__1::complex<double>, -1,
      -1, 0, -1, -1>, 0>, 8, Eigen::DenseShape, Eigen::DenseShape, std::__1::complex<stan::math::var>, std::__1::complex<double> >::product_evaluator' requested here
  EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {}
                                                             ^
lib/eigen_3.3.3/Eigen/src/Core/DenseCoeffsBase.h:144:14: note: in instantiation of member function
      'Eigen::internal::evaluator<Eigen::Product<Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1>, Eigen::Matrix<std::__1::complex<double>, -1, -1, 0,
      -1, -1>, 0> >::evaluator' requested here
      return internal::evaluator<Derived>(derived()).coeff(index);
             ^
lib/eigen_3.3.3/Eigen/src/Core/DenseCoeffsBase.h:181:14: note: in instantiation of member function
      'Eigen::DenseCoeffsBase<Eigen::Product<Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1>, Eigen::Matrix<std::__1::complex<double>, -1, -1, 0, -1,
      -1>, 0>, 0>::coeff' requested here
      return coeff(index);
             ^
test/unit/math/rev/core/std_complex_test.cpp:1653:13: note: in instantiation of member function
      'Eigen::DenseCoeffsBase<Eigen::Product<Eigen::Matrix<std::__1::complex<stan::math::var>, -1, -1, 0, -1, -1>, Eigen::Matrix<std::__1::complex<double>, -1, -1, 0, -1,
      -1>, 0>, 0>::operator()' requested here
  auto a = z(0);
            ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:981:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A1, B_0, C4, T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:982:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A2, B_0, C8, B_0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:984:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A0, B_0, C1, T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:985:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A1, B_0, C5, T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:986:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A2, B_0, C9, B_0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:988:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A0, B_0, C2,  T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:989:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A1, B_0, C6,  T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:990:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A2, B_0, C10, B_0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:992:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A0, B_0, C3 , T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:993:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A1, B_0, C7,  T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(0);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:994:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A2, B_0, C11, B_0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:1000:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(1);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:980:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A0, B_0, C0, T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:1000:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(1);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:981:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A1, B_0, C4, T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:1000:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(1);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:982:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A2, B_0, C8, B_0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:1000:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(1);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:984:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A0, B_0, C1, T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:1000:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(1);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:985:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A1, B_0, C5, T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:1000:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(1);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:986:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A2, B_0, C9, B_0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:1000:13: error: no matching member function for call to 'madd'
            EIGEN_GEBP_ONESTEP(1);
            ^~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:988:22: note: expanded from macro 'EIGEN_GEBP_ONESTEP'
              traits.madd(A0, B_0, C2,  T0); \
              ~~~~~~~^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate template ignored: deduced conflicting types for parameter 'AccPacketType'
      ('complex<stan::math::var>' vs. 'complex<double>')
  EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                           ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.
make: *** [test/unit/math/rev/core/std_complex_test.o] Error 1
make -j8 test/unit/math/rev/core/std_complex_test failed
exit now (12/16/19 17:04:13 EST)

The g++6 errors are a bit more informative and contains this hint (my emphasis with **):

lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:984:15: note:  
 deduced conflicting types for parameter 'AccPacketType' 
('**std::complex<stan::math::var>**' and 
'Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket
 {aka **std::complex<double>**}')
               traits.madd(A0, B_0, C1, T0); \

among the error novel output the start of which I repeat below.

In file included from lib/eigen_3.3.3/Eigen/Core:470:0,
                 from lib/eigen_3.3.3/Eigen/Dense:1,
                 from ./stan/math/prim/mat/fun/Eigen.hpp:13,
                 from ./stan/math/rev/mat.hpp:4,
                 from ./stan/math.hpp:148,
                 from ./test/unit/math/is_finite.hpp:4,
                 from ./test/unit/math/test_ad.hpp:5,
                 from test/unit/math/rev/core/std_complex_test.cpp:1:
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h: In instantiation of 'void Eigen::internal::gebp_kernel<LhsScalar, RhsScalar, Index, DataMapper, mr, nr, ConjugateLhs, ConjugateRhs>::operator()(const DataMapper&, const LhsScalar*, const RhsScalar*, Index, Index, Index, Eigen::internal::gebp_kernel<LhsScalar, RhsScalar, Index, DataMapper, mr, nr, ConjugateLhs, ConjugateRhs>::ResScalar, Index, Index, Index, Index) [with LhsScalar = std::complex<stan::math::var>; RhsScalar = std::complex<double>; Index = long int; DataMapper = Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>; int mr = 2; int nr = 4; bool ConjugateLhs = false; bool ConjugateRhs = false; Eigen::internal::gebp_kernel<LhsScalar, RhsScalar, Index, DataMapper, mr, nr, ConjugateLhs, ConjugateRhs>::ResScalar = std::complex<stan::math::var>]':
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralMatrixMatrix.h:194:15:   required from 'static void Eigen::internal::general_matrix_matrix_product<Index, LhsScalar, LhsStorageOrder, ConjugateLhs, RhsScalar, RhsStorageOrder, ConjugateRhs, 0>::run(Index, Index, Index, const LhsScalar*, Index, const RhsScalar*, Index, Eigen::internal::general_matrix_matrix_product<Index, LhsScalar, LhsStorageOrder, ConjugateLhs, RhsScalar, RhsStorageOrder, ConjugateRhs, 0>::ResScalar*, Index, Eigen::internal::general_matrix_matrix_product<Index, LhsScalar, LhsStorageOrder, ConjugateLhs, RhsScalar, RhsStorageOrder, ConjugateRhs, 0>::ResScalar, Eigen::internal::level3_blocking<LhsScalar, RhsScalar>&, Eigen::internal::GemmParallelInfo<Index>*) [with Index = long int; LhsScalar = std::complex<stan::math::var>; int LhsStorageOrder = 0; bool ConjugateLhs = false; RhsScalar = std::complex<double>; int RhsStorageOrder = 0; bool ConjugateRhs = false; Eigen::internal::general_matrix_matrix_product<Index, LhsScalar, LhsStorageOrder, ConjugateLhs, RhsScalar, RhsStorageOrder, ConjugateRhs, 0>::ResScalar = std::complex<stan::math::var>]'
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralMatrixMatrix.h:226:14:   required from 'void Eigen::internal::gemm_functor<Scalar, Index, Gemm, Lhs, Rhs, Dest, BlockingType>::operator()(Index, Index, Index, Index, Eigen::internal::GemmParallelInfo<Index>*) const [with Scalar = std::complex<stan::math::var>; Index = long int; Gemm = Eigen::internal::general_matrix_matrix_product<long int, std::complex<stan::math::var>, 0, false, std::complex<double>, 0, false, 0>; Lhs = Eigen::Matrix<std::complex<stan::math::var>, -1, -1>; Rhs = Eigen::Matrix<std::complex<double>, -1, -1>; Dest = Eigen::Matrix<std::complex<stan::math::var>, -1, -1>; BlockingType = Eigen::internal::gemm_blocking_space<0, std::complex<stan::math::var>, std::complex<double>, -1, -1, -1, 1, false>]'
lib/eigen_3.3.3/Eigen/src/Core/products/Parallelizer.h:97:7:   required from 'void Eigen::internal::parallelize_gemm(const Functor&, Index, Index, Index, bool) [with bool Condition = true; Functor = Eigen::internal::gemm_functor<std::complex<stan::math::var>, long int, Eigen::internal::general_matrix_matrix_product<long int, std::complex<stan::math::var>, 0, false, std::complex<double>, 0, false, 0>, Eigen::Matrix<std::complex<stan::math::var>, -1, -1>, Eigen::Matrix<std::complex<double>, -1, -1>, Eigen::Matrix<std::complex<stan::math::var>, -1, -1>, Eigen::internal::gemm_blocking_space<0, std::complex<stan::math::var>, std::complex<double>, -1, -1, -1, 1, false> >; Index = long int'
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralMatrixMatrix.h:484:9:   required from 'static void Eigen::internal::generic_product_impl<Lhs, Rhs, Eigen::DenseShape, Eigen::DenseShape, 8>::scaleAndAddTo(Dest&, const Lhs&, const Rhs&, const Scalar&) [with Dest = Eigen::Matrix<std::complex<stan::math::var>, -1, -1>; Lhs = Eigen::Matrix<std::complex<stan::math::var>, -1, -1>; Rhs = Eigen::Matrix<std::complex<double>, -1, -1>; Eigen::internal::generic_product_impl<Lhs, Rhs, Eigen::DenseShape, Eigen::DenseShape, 8>::Scalar = std::complex<stan::math::var>]'
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralMatrixMatrix.h:435:20:   required from 'static void Eigen::internal::generic_product_impl<Lhs, Rhs, Eigen::DenseShape, Eigen::DenseShape, 8>::evalTo(Dst&, const Lhs&, const Rhs&) [with Dst = Eigen::Matrix<std::complex<stan::math::var>, -1, -1>; Lhs = Eigen::Matrix<std::complex<stan::math::var>, -1, -1>; Rhs = Eigen::Matrix<std::complex<double>, -1, -1>]'
lib/eigen_3.3.3/Eigen/src/Core/ProductEvaluators.h:124:75:   required from 'Eigen::internal::product_evaluator<Eigen::Product<Lhs, Rhs, Option>, ProductTag, LhsShape, RhsShape>::product_evaluator(const XprType&) [with Lhs = Eigen::Matrix<std::complex<stan::math::var>, -1, -1>; Rhs = Eigen::Matrix<std::complex<double>, -1, -1>; int Options = 0; int ProductTag = 8; LhsShape = Eigen::DenseShape; RhsShape = Eigen::DenseShape; typename Eigen::internal::traits<typename Eigen::Product<Lhs, Rhs, Option>::Rhs>::Scalar = std::complex<double>; typename Eigen::internal::traits<typename Eigen::Product<Lhs, Rhs, Option>::Lhs>::Scalar = std::complex<stan::math::var>; Eigen::internal::product_evaluator<Eigen::Product<Lhs, Rhs, Option>, ProductTag, LhsShape, RhsShape>::XprType = Eigen::Product<Eigen::Matrix<std::complex<stan::math::var>, -1, -1>, Eigen::Matrix<std::complex<double>, -1, -1>, 0>]'
lib/eigen_3.3.3/Eigen/src/Core/ProductEvaluators.h:35:70:   required from 'Eigen::internal::evaluator<Eigen::Product<Lhs, Rhs, Option> >::evaluator(const XprType&) [with Lhs = Eigen::Matrix<std::complex<stan::math::var>, -1, -1>; Rhs = Eigen::Matrix<std::complex<double>, -1, -1>; int Options = 0; Eigen::internal::evaluator<Eigen::Product<Lhs, Rhs, Option> >::XprType = Eigen::Product<Eigen::Matrix<std::complex<stan::math::var>, -1, -1>, Eigen::Matrix<std::complex<double>, -1, -1>, 0>]'
lib/eigen_3.3.3/Eigen/src/Core/DenseCoeffsBase.h:144:24:   required from 'Eigen::DenseCoeffsBase<Derived, 0>::CoeffReturnType Eigen::DenseCoeffsBase<Derived, 0>::coeff(Eigen::Index) const [with Derived = Eigen::Product<Eigen::Matrix<std::complex<stan::math::var>, -1, -1>, Eigen::Matrix<std::complex<double>, -1, -1>, 0>; Eigen::DenseCoeffsBase<Derived, 0>::CoeffReturnType = const std::complex<stan::math::var>; Eigen::Index = long int]'
lib/eigen_3.3.3/Eigen/src/Core/DenseCoeffsBase.h:181:19:   required from 'Eigen::DenseCoeffsBase<Derived, 0>::CoeffReturnType Eigen::DenseCoeffsBase<Derived, 0>::operator()(Eigen::Index) const [with Derived = Eigen::Product<Eigen::Matrix<std::complex<stan::math::var>, -1, -1>, Eigen::Matrix<std::complex<double>, -1, -1>, 0>; Eigen::DenseCoeffsBase<Derived, 0>::CoeffReturnType = const std::complex<stan::math::var>; Eigen::Index = long int]'
test/unit/math/rev/core/std_complex_test.cpp:1653:15:   required from here
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:980:15: error: no matching function for call to 'Eigen::internal::gebp_traits<std::complex<stan::math::var>, std::complex<double>, false, false>::madd(Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::LhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::AccPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&)'
               traits.madd(A0, B_0, C0, T0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate: template<class LhsPacketType, class RhsPacketType, class AccPacketType> void Eigen::internal::gebp_traits<_LhsScalar, _RhsScalar, _ConjLhs, _ConjRhs>::madd(const LhsPacketType&, const RhsPacketType&, AccPacketType&, AccPacketType&) const [with LhsPacketType = LhsPacketType; RhsPacketType = RhsPacketType; AccPacketType = AccPacketType; _LhsScalar = std::complex<stan::math::var>; _RhsScalar = std::complex<double>; bool _ConjLhs = false; bool _ConjRhs = false]
   EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                            ^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note:   template argument deduction/substitution failed:
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:980:15: note:   deduced conflicting types for parameter 'AccPacketType' ('std::complex<stan::math::var>' and 'Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket {aka std::complex<double>}')
               traits.madd(A0, B_0, C0, T0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:981:15: error: no matching function for call to 'Eigen::internal::gebp_traits<std::complex<stan::math::var>, std::complex<double>, false, false>::madd(Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::LhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::AccPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&)'
               traits.madd(A1, B_0, C4, T0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate: template<class LhsPacketType, class RhsPacketType, class AccPacketType> void Eigen::internal::gebp_traits<_LhsScalar, _RhsScalar, _ConjLhs, _ConjRhs>::madd(const LhsPacketType&, const RhsPacketType&, AccPacketType&, AccPacketType&) const [with LhsPacketType = LhsPacketType; RhsPacketType = RhsPacketType; AccPacketType = AccPacketType; _LhsScalar = std::complex<stan::math::var>; _RhsScalar = std::complex<double>; bool _ConjLhs = false; bool _ConjRhs = false]
   EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                            ^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note:   template argument deduction/substitution failed:
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:981:15: note:   deduced conflicting types for parameter 'AccPacketType' ('std::complex<stan::math::var>' and 'Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket {aka std::complex<double>}')
               traits.madd(A1, B_0, C4, T0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:982:15: error: no matching function for call to 'Eigen::internal::gebp_traits<std::complex<stan::math::var>, std::complex<double>, false, false>::madd(Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::LhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::AccPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&)'
               traits.madd(A2, B_0, C8, B_0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate: template<class LhsPacketType, class RhsPacketType, class AccPacketType> void Eigen::internal::gebp_traits<_LhsScalar, _RhsScalar, _ConjLhs, _ConjRhs>::madd(const LhsPacketType&, const RhsPacketType&, AccPacketType&, AccPacketType&) const [with LhsPacketType = LhsPacketType; RhsPacketType = RhsPacketType; AccPacketType = AccPacketType; _LhsScalar = std::complex<stan::math::var>; _RhsScalar = std::complex<double>; bool _ConjLhs = false; bool _ConjRhs = false]
   EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                            ^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note:   template argument deduction/substitution failed:
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:982:15: note:   deduced conflicting types for parameter 'AccPacketType' ('std::complex<stan::math::var>' and 'Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket {aka std::complex<double>}')
               traits.madd(A2, B_0, C8, B_0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:984:15: error: no matching function for call to 'Eigen::internal::gebp_traits<std::complex<stan::math::var>, std::complex<double>, false, false>::madd(Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::LhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::AccPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&)'
               traits.madd(A0, B_0, C1, T0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate: template<class LhsPacketType, class RhsPacketType, class AccPacketType> void Eigen::internal::gebp_traits<_LhsScalar, _RhsScalar, _ConjLhs, _ConjRhs>::madd(const LhsPacketType&, const RhsPacketType&, AccPacketType&, AccPacketType&) const [with LhsPacketType = LhsPacketType; RhsPacketType = RhsPacketType; AccPacketType = AccPacketType; _LhsScalar = std::complex<stan::math::var>; _RhsScalar = std::complex<double>; bool _ConjLhs = false; bool _ConjRhs = false]
   EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                            ^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note:   template argument deduction/substitution failed:
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:984:15: note:   deduced conflicting types for parameter 'AccPacketType' ('std::complex<stan::math::var>' and 'Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket {aka std::complex<double>}')
               traits.madd(A0, B_0, C1, T0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:985:15: error: no matching function for call to 'Eigen::internal::gebp_traits<std::complex<stan::math::var>, std::complex<double>, false, false>::madd(Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::LhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::AccPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&)'
               traits.madd(A1, B_0, C5, T0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate: template<class LhsPacketType, class RhsPacketType, class AccPacketType> void Eigen::internal::gebp_traits<_LhsScalar, _RhsScalar, _ConjLhs, _ConjRhs>::madd(const LhsPacketType&, const RhsPacketType&, AccPacketType&, AccPacketType&) const [with LhsPacketType = LhsPacketType; RhsPacketType = RhsPacketType; AccPacketType = AccPacketType; _LhsScalar = std::complex<stan::math::var>; _RhsScalar = std::complex<double>; bool _ConjLhs = false; bool _ConjRhs = false]
   EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                            ^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note:   template argument deduction/substitution failed:
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:985:15: note:   deduced conflicting types for parameter 'AccPacketType' ('std::complex<stan::math::var>' and 'Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket {aka std::complex<double>}')
               traits.madd(A1, B_0, C5, T0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:986:15: error: no matching function for call to 'Eigen::internal::gebp_traits<std::complex<stan::math::var>, std::complex<double>, false, false>::madd(Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::LhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::AccPacket&, Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket&)'
               traits.madd(A2, B_0, C9, B_0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note: candidate: template<class LhsPacketType, class RhsPacketType, class AccPacketType> void Eigen::internal::gebp_traits<_LhsScalar, _RhsScalar, _ConjLhs, _ConjRhs>::madd(const LhsPacketType&, const RhsPacketType&, AccPacketType&, AccPacketType&) const [with LhsPacketType = LhsPacketType; RhsPacketType = RhsPacketType; AccPacketType = AccPacketType; _LhsScalar = std::complex<stan::math::var>; _RhsScalar = std::complex<double>; bool _ConjLhs = false; bool _ConjRhs = false]
   EIGEN_STRONG_INLINE void madd(const LhsPacketType& a, const RhsPacketType& b, AccPacketType& c, AccPacketType& tmp) const
                            ^~~~
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:435:28: note:   template argument deduction/substitution failed:
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:986:15: note:   deduced conflicting types for parameter 'AccPacketType' ('std::complex<stan::math::var>' and 'Eigen::internal::gebp_kernel<std::complex<stan::math::var>, std::complex<double>, long int, Eigen::internal::blas_data_mapper<std::complex<stan::math::var>, long int, 0, 0>, 2, 4, false, false>::RhsPacket {aka std::complex<double>}')
               traits.madd(A2, B_0, C9, B_0); \
               ^
lib/eigen_3.3.3/Eigen/src/Core/products/GeneralBlockPanelKernel.h:999:13: note: in expansion of macro 'EIGEN_GEBP_ONESTEP'
             EIGEN_GEBP_ONESTEP(0);
             ^~~~~~~~~~~~~~~~~~
...

On clang++, after the result type is fixed, the error message is

../eigen-git-mirror\Eigen/src/Core/util/BlasUtil.h:127:79: fatal error: cannot convert 'const std::complex<stan::math::var>' to 'double' without a conversion operator
  EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE To run(const From& x) { return To(x); }
                                                                              ^~~~
../eigen-git-mirror\Eigen/src/Core/GeneralProduct.h:247:66: note: in instantiation of member function 'Eigen::internal::get_factor<std::complex<stan::math::var>, double>::run' requested here
    RhsScalar compatibleAlpha = get_factor<ResScalar,RhsScalar>::run(actualAlpha);

I looked at it, and get_factor is used to convert its first template argument into its second, so var into double, which is obviously wrong. I thought about what kinds of things may lead Eigen to believe this kind of conversion could happen. The operator* free function for var and double is defined, so that wasn’t it. I did notice this code that needs to die regardless, along with anything similar that might exist elsewhere:

If that doesn’t help, I’ll keep looking.

BTW, earlier today I found someone on stackoverflow who illustrated a similar issue with float and double, after enabling the binary return type. It only happened with dynamic size matrices. The workaround from ggael was to use lazy product. I will check tomorrow to see if this affects my implementation also, since I usually use fixed size. Still, it doesn’t seem quite right that eigen would attempt to convert var to double rather than the other way around, so I’m not sure what’s triggering the errors yet.

Mine also has the problem of attempting to convert complex<var> to double for dynamic matrices (but not constant size ones, nor when using lazy product). I also compiled the stack overflow example I mentioned last night, which didn’t include the errors in the post. What happens in theirs is different from ours. In theirs, Eigen creates SIMD vector types annotations that represent packed floats (qty 4 at a time) and doubles (qty 2 at a time). The compiler error in their case is essentially that ScalarBinaryOpTraits<vec4f,vec2d,Op>::ResultType wasn’t defined, which was true. The user had only defined ScalarBinaryOpTraits<float,double,Op>::ResultType. In ours, Eigen is attempting to convert complex<var> to double, rather than double to complex<var>, which seems like it might be a matter of telling eigen that the appropriate cast is possible from double, or by defining the relevant matrix product to do the cast first and then delegate back. Still looking.

The explicit var(const complex<double>&) is in develop, not something I added for this branch.

@bgoodri — It looks like you were the one who added the constructor. What’s the intended use case?

I can see the desire to have a complex with 0 imaginary part act like real, but I don’t think that makes sense for C++ types. I think the following two cases should be parallel:

complex<double> x;
var y{x};
complex<double> x{3, 0};
double y{x};

Given that the second isn’t legal,

cplx.cpp:6:10: error: no viable conversion from 'std::complex<double>' to 'double'
  double y{x};

I don’t think the first should be, either.

1 Like

I remember having to delete it from my branch way back also. I know you wouldn’t add something like that in this PR :)

IIRC, there was no intended use case. It was just to prevent a segfault in a program like

#include <stan/math.hpp>
#include <iostream>
#include <complex>

int main() {
  stan::math::var x = 1;
  std::complex<stan::math::var> z = x;
  std::cout << "imaginary part is " << z.imag().val() << std::endl;
  return 0;
}

If those constructors are getting in the way of having something actually useful, then change them or get rid of them.

Are you suggesting some kind of fix to result type? Is that ReturnType in ScalaryBinaryOpTraits?

I’d like to try the Eigen 3.4 beta, but I can’t find it to download. Does anyone know if it’s the master branch on GitLab?

I’m going to play around with their built-in autodiff to see if it works as expected with these mixed types. It’s all in a single source file, AutoDiffScalar.h. It uses these two traits classes:

  528 template<typename DerType, typename BinOp>
  529 struct ScalarBinaryOpTraits<AutoDiffScalar<DerType>,typename DerType::Scalar,BinOp>
  530 {
  531   typedef AutoDiffScalar<DerType> ReturnType;
  532 };
  533 
  534 template<typename DerType, typename BinOp>
  535 struct ScalarBinaryOpTraits<typename DerType::Scalar,AutoDiffScalar<DerType>, BinOp>
  536 {
  537   typedef AutoDiffScalar<DerType> ReturnType;
  538 };

I went through what we did for var and I realized there’s another traits class that could be defined, so I gave that a shot:

template <>
struct NumTraits<std::complex<stan::math::var>> : GenericNumTraits<std::complex<stan::math::var>> {
  using Real = std::complex<stan::math::var>;
  using NonInteger = std::complex<stan::math::var>;
  using Nested = std::complex<stan::math::var>;

  /**
   * Return the precision for <code>stan::math::var</code> delegates
   * to precision for <code>douboe</code>.
   *
   * @return precision
   */
  static inline std::complex<stan::math::var> dummy_precision() {
    return NumTraits<double>::dummy_precision();
  }

  enum {
    /**
     * complex<var> is complex.
     */
    IsComplex = 1,

    /**
     * complex<var> is not an integer.
     */
    IsInteger = 0,

    /**
     * complex<var> is signed.
     */
    IsSigned = 1,

    /**
     * complex<var> does not require initialization.
     */
    RequireInitialization = 0,

    /**
     * Quadruple the cost of copying a double.
     */
    ReadCost = NumTraits<std::complex<double>>::ReadCost,

    /**
     * This is just forward cost, but it's the cost of a single
     * addition (plus memory overhead) in the forward direction.
     */
    AddCost = NumTraits<std::complex<double>>::AddCost,

    /**
     * Multiply cost is single multiply going forward, but there's
     * also memory allocation cost.
     */
    MulCost = NumTraits<std::complex<double>>::MulCost
  };

  /**
   * Return the number of decimal digits that can be represented
   * without change.  Delegates to
   * <code>std::numeric_limits<double>::digits10()</code>.
   */
  static int digits10() { return std::numeric_limits<double>::digits10; }
};

No luck. All hell breaks loose after I add that because it somehow starts trying to assign complex<var> to var in clang++ and std::complex<double> to double in g++9. I’d have thought setting IsComplex to 1 would deal with that kind of thing.

It appears the ‘offending’ line is

../eigen-git-mirror\Eigen/src/Core/GeneralProduct.h:247:66: note: in instantiation of member function 'Eigen::internal::get_factor<std::complex<stan::math::var>, double>::run' requested here
    RhsScalar compatibleAlpha = get_factor<ResScalar,RhsScalar>::run(actualAlpha);

This just converts a factor will get used in the matrix product from a type that is compatible with the result type (which would be complex) into a type that can be stored and kept along with the rhs type, which is double. If I had to guess from reading the lines above line 247, it is a form of preconditioning by reading something from both the left and right hand sides first, and that preconditioning factor is then made type compatible with the Rhs.

Thus, I suggest trying to define Eigen::internal::getFactor<complex,double>::run so that it pulls out the “sign” and magnitude of its argument (a complex number) into a double, and see what happens. I will try that now.

It may not have been apparent due to the other problem you ran into, but I suspect you’ve successfully already set the appropriate ScalarBinaryOpTraits::ReturnType in the manner we discussed. Instead (see posts above), I believe we’re now running into a problem with what eigen does with dynamic sized matrices of different types (complex and double), a problem that doesn’t manifest if fixed size matrices are used, or if lazy product is used (see stack overflow link above). Specifically, it seems like the general matrix product it is using first preconditions the right hand side operand (the double matrix or vector), using a factor that is initialized from both the right and left hand operands. That is why it is trying to convert something that is complex<var> back into double.

OK. The example program will be fixed with the complex PR, assuming I can ever get the Eigen traits/overloads/specializations sorted.

They keep calling it something like 3.3 with really high numbers after that. It won’t be “3.4” until after they do the official release, but everything is in the default branch on github’s mirror.

Bob I goofed around with some of the metaprogramming for this. I can make a PR with just the metaprogramming stuff onto your branch or you can just take the below files

is_complex.hpp - require_complex_t/etc - scale/value_type specialization

The metaprogramming helps remove a good bit of stuff

I’m looking around to determine what Eigen normally does if it knows it has, say, a complex<double> matrix times a regular double matrix. It looks like this is one of the calls, where we see numext::realref applied to the alpha factor.

We can also see that there is, indeed, a get_factor defined for the case where the To type is the matching real type of a corresponding complex type. In that case, it uses numext::real.***

MathFunctions.h has the implementations of real and real_ref.

*** If I’m reading it right, this implies that if the double matrix were, instead, a var matrix, then the general matrix routine would apply the real function to the complex<var> alpha factor to get a var compatibleAlpha factor.