Parameters converted to `double` when compiling with external C++ and MPI map_rect()

Dang good question. I think this mpicxx is using g++. I usually have a little better luck with clang++. I’ll try to compile this with clang++ in a bit.

In my initial skim of the output you posted, this seems to be the operative distinction between which arguments are treated as var and which are treated as double.

1 Like

I think what’s happening is that the MPI thing has code for computing gradients with respect to what you’ve called the dummy variables separately from gradients with respect to the shared parameters.

Even though the dummy variables aren’t being used, the type information is getting used when allocating the wth/yini local variables:

using local_scalar_t__ = stan::promote_args_t<T0__, T1__, T2__>;
...
Eigen::Matrix<local_scalar_t__, -1, 1> yini;

I don’t think this is anything to worry about. Just implement the signature. You might be able to put a throw in it too – I don’t think this function needs to get called so hopefully it doesn’t even though it gets compiled.

Here’s the clang compile output:

mpicxx -std=c++1y -D_REENTRANT -Wno-sign-compare    -Wno-delete-non-virtual-dtor  -I stan/lib/stan_math/lib/tbb_2019_U8/include -O3 -I src -I stan/src -I lib/rapidjson_1.1.0/ -I stan/lib/stan_math/ -I stan/lib/stan_math/lib/eigen_3.3.7 -I stan/lib/stan_math/lib/boost_1.72.0 -I stan/lib/stan_math/lib/sundials_5.2.0/include    -DBOOST_DISABLE_ASSERTS   -DSTAN_MPI   -c -include /home/bbales2/tmp/cmdstan-develop/cont.hpp -x c++ -o wheat.o wheat.hpp
wheat.hpp:1903:15: error: call to deleted function 'sigmoid'
    vrn_fac = sigmoid(
              ^~~~~~~
wheat.hpp:2011:9: note: in instantiation of function template specialization 'wheat_model_namespace::continuous_dydt<stan::math::var, double, stan::math::var>' requested
      here
        continuous_dydt(y, theta,
        ^
wheat.hpp:2243:9: note: in instantiation of function template specialization 'wheat_model_namespace::euler_integrate_ode<stan::math::var, double, stan::math::var, double>'
      requested here
        euler_integrate_ode(yini,
        ^
wheat.hpp:2414:7: note: in instantiation of function template specialization 'wheat_model_namespace::run_model<double, stan::math::var, double>' requested here
      run_model(theta, dummy, x_r, x_i, pstream__), "assigning variable sim");
      ^
wheat.hpp:2454:8: note: in instantiation of function template specialization 'wheat_model_namespace::parallel_log_likelihood<double, stan::math::var>' requested here
return parallel_log_likelihood(theta, dummy, x_r, x_i, pstream__);
       ^
stan/lib/stan_math/stan/math/rev/functor/map_rect_reduce.hpp:69:21: note: in instantiation of function template specialization
      'wheat_model_namespace::parallel_log_likelihood_functor__::operator()<double, stan::math::var>' requested here
    vector_v fx_v = F()(shared_params, job_specific_params_v, x_r, x_i, msgs);

I’m afraid I don’t quite follow the logic. Are you here explaining 1 or 2:

  1. why x is var
  2. why sen, mid_pt, and rate are double?

If it’s 1, that part doesn’t really bother me as much as 2:

If you are explaining 2, can you please explain it again (using small words so I can be sure to get it). :-)

Both haha

There are two arguments to the mapped function that might contain vars, phi or theta (defined here: Stan Functions Reference).

It looks like when using map_rect, the gradients with respect to each of these arguments are computed separately. When one is vars, the other is doubles. When one is doubles, the other is vars. @wds15 can you confirm if this is true or not?

Your theta matches the type of the first argument to the mapped function (phi) and your wth/yini local variables match the type of the second argument cause of how the local variables are defined.

That’s my hunch at least. @wds15 will know if I’m wrong or not. The map_rect code is rather involved so easier to ask than digging into it.

No. That’s not what is happening.

Just look at Stan math rev functor map_rect_reduce.hpp.

1 Like

I think I get it now. @bbbales2, I think you were right that I can safely implement the function signature it’s asking for. Inspecting stan/math/rev /functor/map_rect_reduce.hpp I found these lines at the end of the file:

#define STAN_REGISTER_MPI_MAP_RECT_ALL(CALLID, FUNCTOR)       \
  STAN_REGISTER_MPI_MAP_RECT(CALLID, FUNCTOR, double, double) \
  STAN_REGISTER_MPI_MAP_RECT(CALLID, FUNCTOR, double, var)    \
  STAN_REGISTER_MPI_MAP_RECT(CALLID, FUNCTOR, var, double)    \
  STAN_REGISTER_MPI_MAP_RECT(CALLID, FUNCTOR, var, var)

If I understand this correctly, the code is basically defining all possible permutations of the types for Phi (i.e. shared_params) and theta (i.e. job_specific_params) even though only some of these would actually be invoked while sampling. @wds15, is that correct?

If I’m right, then I need not worry about my original concern:

I should be able to solve the specific problem I mentioned at the outset by adding a templated expression like so:

    template<typename T1, typename T2, typename T3, typename T4>
    typename boost::math::tools::promote_args<T1, T2, T3, T4>::type
      sigmoid(const T1& x, const T2& sen, const T3& mid_pt, const T4& rate, std::ostream* pstream__) {
        throw std::logic_error("not implemented");
      }

This would allow everything to compile and would throw an error if it were ever actually called during sampling. Does that all make sense?

1 Like

Sounds about right, yes.

Yeah, this looks good!