Skip to content

Indexing arrays of matrices within operations results in Eigen compilation errors #3396

Description

@andrjohns

Debugging a build failure for the ctsem R package against the development rstan, and narrowed it down to some Eigen-expression-issues with Stan's indexing.

Given model:

data {
  real y_mean;
}

parameters {
  real y;
}

model {
  matrix[2, 2] m1 = [[0,0],[0,0]];
  array[1,1] matrix[2, 2] m2 = {{ m1 }};
  matrix[2,2] res;

  // No compilation error
  res = m1 * m1';

  // Compilation error
  res = m2[1,1] * m2[1,1]';

  y ~ normal(y_mean, 1);
}

Compilation fails with:

--- Compiling C++ code ---
g++ -std=c++17 -pthread -D_REENTRANT -Wno-sign-compare -Wno-ignored-attributes -Wno-class-memaccess      -isystem stan/lib/stan_math/lib/tbb_2020.3/include    -O3 -I src -I stan/src -I stan/lib/rapidjson_1.1.0/ -I lib/CLI11-1.9.1/ -I stan/lib/stan_math/ -isystem stan/lib/stan_math/lib/eigen_5.0.1 -isystem stan/lib/stan_math/lib/boost_1.87.0 -isystem stan/lib/stan_math/lib/sundials_6.1.1/include -isystem stan/lib/stan_math/lib/sundials_6.1.1/src/sundials    -DBOOST_DISABLE_ASSERTS          -c -Wno-ignored-attributes   -x c++ -o examples/bernoulli/model.o examples/bernoulli/model.hpp
In file included from stan/lib/stan_math/lib/eigen_5.0.1/Eigen/Core:418,
                 from stan/lib/stan_math/lib/eigen_5.0.1/Eigen/Dense:1,
                 from stan/lib/stan_math/stan/math/prim/fun/Eigen.hpp:32,
                 from stan/lib/stan_math/stan/math/rev/core/Eigen_NumTraits.hpp:4,
                 from stan/lib/stan_math/stan/math/rev/core.hpp:4,
                 from stan/src/stan/model/model_base.hpp:8,
                 from stan/src/stan/model/model_header.hpp:4:
stan/lib/stan_math/lib/eigen_5.0.1/Eigen/src/Core/products/GeneralMatrixMatrix.h: In instantiation of ‘void Eigen::internal::gemm_functor<Scalar, Index, Gemm, Lhs, Rhs, Dest, BlockingType>::operator()(Index, Index, Index, Index, Eigen::internal::GemmParallelInfo<Index>*) const [with Scalar = double; Index = long int; Gemm = Eigen::internal::general_matrix_matrix_product<long int, double, 0, false, double, 1, false, 0, 1>; Lhs = Eigen::Matrix<double, -1, -1>; Rhs = stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >; Dest = Eigen::Matrix<double, -1, -1>; BlockingType = Eigen::internal::gemm_blocking_space<0, double, double, -1, -1, -1, 1, false>]’:
stan/lib/stan_math/lib/eigen_5.0.1/Eigen/src/Core/products/Parallelizer.h:110:7:   required from ‘void Eigen::internal::parallelize_gemm(const Functor&, Index, Index, Index, bool) [with bool Condition = true; Functor = gemm_functor<double, long int, general_matrix_matrix_product<long int, double, 0, false, double, 1, false, 0, 1>, Eigen::Matrix<double, -1, -1>, stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::Matrix<double, -1, -1>, gemm_blocking_space<0, double, double, -1, -1, -1, 1, false> >; Index = long int]’
  110 |   func(0, rows, 0, cols);
      |   ~~~~^~~~~~~~~~~~~~~~~~
stan/lib/stan_math/lib/eigen_5.0.1/Eigen/src/Core/products/GeneralMatrixMatrix.h:449:107:   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<double, -1, -1>; Lhs = Eigen::Matrix<double, -1, -1>; Rhs = stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >; Scalar = double]’
  449 |     internal::parallelize_gemm<(Dest::MaxRowsAtCompileTime > 32 || Dest::MaxRowsAtCompileTime == Dynamic)>(
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
  450 |         GemmFunctor(lhs, rhs, dst, actualAlpha, blocking), a_lhs.rows(), a_rhs.cols(), a_lhs.cols(),
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~       
  451 |         Dest::Flags & RowMajorBit);
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~                                                                         
stan/lib/stan_math/lib/eigen_5.0.1/Eigen/src/Core/products/GeneralMatrixMatrix.h:392: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<double, -1, -1>; Lhs = Eigen::Matrix<double, -1, -1>; Rhs = stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >]’
  392 |       scaleAndAddTo(dst, lhs, rhs, Scalar(1));
      |       ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
stan/lib/stan_math/lib/eigen_5.0.1/Eigen/src/Core/ProductEvaluators.h:112:75:   required from ‘Eigen::internal::product_evaluator<Eigen::Product<Lhs, Rhs, Option>, ProductTag, LhsShape, RhsShape>::product_evaluator(const XprType&) [with Lhs = Eigen::Matrix<double, -1, -1>; Rhs = stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >; int Options = 0; int ProductTag = 8; LhsShape = Eigen::DenseShape; RhsShape = Eigen::DenseShape; typename Eigen::internal::traits<typename Eigen::Product<Lhs, Rhs, Option>::Lhs>::Scalar = double; typename Eigen::Product<Lhs, Rhs, Option>::Lhs = Eigen::Matrix<double, -1, -1>; typename Eigen::internal::traits<typename Eigen::Product<Lhs, Rhs, Option>::Rhs>::Scalar = double; typename Eigen::Product<Lhs, Rhs, Option>::Rhs = stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >; XprType = Eigen::Product<Eigen::Matrix<double, -1, -1>, stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >, 0>]’
  112 |     generic_product_impl<Lhs, Rhs, LhsShape, RhsShape, ProductTag>::evalTo(m_result, xpr.lhs(), xpr.rhs());
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
stan/lib/stan_math/lib/eigen_5.0.1/Eigen/src/Core/ProductEvaluators.h:35:90:   required from ‘Eigen::internal::evaluator<Eigen::Product<Lhs, Rhs, Option> >::evaluator(const XprType&) [with Lhs = Eigen::Matrix<double, -1, -1>; Rhs = stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >; int Options = 0; XprType = Eigen::Product<Eigen::Matrix<double, -1, -1>, stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >, 0>]’
   35 |   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(xpr) {}
      |                                                                                          ^
stan/lib/stan_math/stan/math/prim/meta/holder.hpp:277:44:   [ skipping 8 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
stan/src/stan/model/indexing/access_helpers.hpp:92:5:   required from ‘void stan::model::internal::assign_impl(T1&&, T2&&, const char*) [with T1 = Eigen::Matrix<double, -1, -1>&; T2 = stan::math::Holder<Eigen::Product<Eigen::Matrix<double, -1, -1>, stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >, 0>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> > >; stan::require_all_eigen_t<T_desired, T_actual>* <anonymous> = 0]’
   92 |   x = std::forward<T2>(y);
      |   ~~^~~~~~~~~~~~~~~~~~~~~
stan/src/stan/model/indexing/assign.hpp:65:24:   required from ‘void stan::model::assign(T&&, U&&, const char*) [with T = Eigen::Matrix<double, -1, -1>&; U = stan::math::Holder<Eigen::Product<Eigen::Matrix<double, -1, -1>, stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >, 0>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> > >; stan::require_t<std::is_assignable<typename std::decay<_Tp>::type&, typename std::decay<_Tp2>::type> >* <anonymous> = 0; stan::require_all_not_std_vector_t<T1, T2>* <anonymous> = 0; stan::math::require_all_not_tuple_t<T, U>* <anonymous> = 0]’
   65 |   internal::assign_impl(x, std::forward<U>(y), name);
      |   ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
examples/bernoulli/model.hpp:113:28:   required from ‘stan::scalar_type_t<T2> model_model_namespace::model_model::log_prob_impl(VecR&, VecI&, std::ostream*) const [with bool propto__ = false; bool jacobian__ = false; VecR = Eigen::Matrix<double, -1, 1>; VecI = Eigen::Matrix<int, -1, 1>; stan::require_vector_like_t<VecR>* <anonymous> = 0; stan::require_vector_like_vt<std::is_integral, VecI>* <anonymous> = 0; stan::require_not_st_var<VecR>* <anonymous> = 0; stan::scalar_type_t<T2> = double; std::ostream = std::basic_ostream<char>]’
  113 |         stan::model::assign(res,
      |         ~~~~~~~~~~~~~~~~~~~^~~~~
  114 |           stan::math::multiply(
      |           ~~~~~~~~~~~~~~~~~~~~~
  115 |             stan::model::rvalue(m2, "m2", stan::model::index_uni(1),
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  116 |               stan::model::index_uni(1)),
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  117 |             stan::math::transpose(
      |             ~~~~~~~~~~~~~~~~~~~~~~
  118 |               stan::model::rvalue(m2, "m2", stan::model::index_uni(1),
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  119 |                 stan::model::index_uni(1)))), "assigning variable res");
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
examples/bernoulli/model.hpp:375:47:   required from ‘T_ model_model_namespace::model_model::log_prob(Eigen::Matrix<T, -1, 1>&, std::ostream*) const [with bool propto__ = false; bool jacobian__ = false; T_ = double; std::ostream = std::basic_ostream<char>]’
  375 |     return log_prob_impl<propto__, jacobian__>(params_r, params_i, pstream);
      |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
stan/src/stan/model/model_base_crtp.hpp:93:80:   required from ‘double stan::model::model_base_crtp<M>::log_prob(Eigen::VectorXd&, std::ostream*) const [with M = model_model_namespace::model_model; Eigen::VectorXd = Eigen::Matrix<double, -1, 1>; std::ostream = std::basic_ostream<char>]’
   93 |     return static_cast<const M*>(this)->template log_prob<false, false, double>(
      |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
   94 |         theta, msgs);
      |         ~~~~~~~~~~~~                                                            
stan/src/stan/model/model_base_crtp.hpp:91:17:   required from here
   91 |   inline double log_prob(Eigen::VectorXd& theta,
      |                 ^~~~~~~~
stan/lib/stan_math/lib/eigen_5.0.1/Eigen/src/Core/products/GeneralMatrixMatrix.h:206:102: error: passing ‘const stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >’ as ‘this’ argument discards qualifiers [-fpermissive]
  206 |     Gemm::run(rows, cols, m_lhs.cols(), &m_lhs.coeffRef(row, 0), m_lhs.outerStride(), &m_rhs.coeffRef(0, col),
      |                                                                                        ~~~~~~~~~~~~~~^~~~~~~~
In file included from stan/lib/stan_math/lib/eigen_5.0.1/Eigen/Core:350:
stan/lib/stan_math/lib/eigen_5.0.1/Eigen/src/Core/DenseCoeffsBase.h:316:59: note:   in call to ‘constexpr Eigen::DenseCoeffsBase<Derived, 1>::Scalar& Eigen::DenseCoeffsBase<Derived, 1>::coeffRef(Eigen::Index, Eigen::Index) [with Derived = stan::math::Holder<Eigen::Transpose<Eigen::Matrix<double, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >; Scalar = double; Eigen::Index = long int]’
  316 |   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Scalar& coeffRef(Index row, Index col) {
      |                                                           ^~~~~~~~
make: *** [make/program:77: examples/bernoulli/model.o] Error 1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions