Trying to follow the examples linked to so far, I’ve tried to implement the usersum, as follows
#include <stan/math.hpp>
using namespace stan;
using namespace std;
template <typename M, require_matrix_t<M>* = nullptr>
inline auto usersum(const M& m, ostream *pstream__) {
using ret_t = return_var_matrix_t<M>;
const double *x = m.data();
int n = m.rows() * m.cols();
// auto ret = support_sum(n, x);
arena_t<ret_t> one(m.rows(), m.cols());
one = 1.0;
arena_t<ret_t> ret = m.sum();
arena_t<ret_t> arena_m = m;
reverse_pass_callback([ret, arena_m, one]() mutable {
arena_m.adj() += one;
});
return ret_t(ret);
}
but there is a pile of link errors of the sort
undefined reference to `boost::math::tools::promote_args<stan::value_type<Eigen::Matrix<stan::math::var_value<double, void>, -1, -1, 0, -1, -1>, void>::type, float, float, float, float, float>::type model_model_namespace::usersum<Eigen::Matrix<stan::math::var_value<double, void>, -1, -1, 0, -1, -1> >(Eigen::Matrix<stan::math::var_value<double, void>, -1, -1, 0, -1, -1> const&, std::ostream*)'
I’m not sure if this is a namespace issue or that the types are wrong or missing an implementation without var? I’m also trying to understand this from the generalized inverse PR but haven’t got it yet.
edit 1 if I namespace the above function in the model_model_namespace, it seems to resolve the link error, but there’s an ambiguity in the overload which I also don’t understand.
/home/duke/src/gist-stan-user-func-ext-c/model.hpp:96:31: error: call of overloaded ‘usersum(Eigen::Matrix<stan::math::var_value<double>, -1, -1>&, std::ostream*&)’ is ambiguous
96 | lp_accum__.add(usersum(m, pstream__));
| ~~~~~~~^~~~~~~~~~~~~~
In file included from <command-line>:
/home/duke/src/gist-stan-user-func-ext-c/support.hpp:9:1: note: candidate: ‘stan::promote_args_t<typename stan::value_type<T, void>::type> model_model_namespace::usersum(const M&, std::ostream*) [with M = Eigen::Matrix<stan::math::var_value<double>, -1, -1>; stan::require_matrix_t<T>* <anonymous> = 0; stan::promote_args_t<typename stan::value_type<T, void>::type> = stan::math::var_value<double>; std::ostream = std::basic_ostream<char>]’
9 | usersum(const M& m, ostream *pstream__) {
| ^~~~~~~
/home/duke/src/gist-stan-user-func-ext-c/model.hpp:28:1: note: candidate: ‘stan::promote_args_t<typename stan::value_type<T, void>::type> model_model_namespace::usersum(const T0__&, std::ostream*) [with T0__ = Eigen::Matrix<stan::math::var_value<double>, -1, -1>; stan::promote_args_t<typename stan::value_type<T, void>::type> = stan::math::var_value<double>; std::ostream = std::basic_ostream<char>]’
28 | usersum(const T0__& m_arg__, std::ostream* pstream__) ;
| ^~~~~~~
edit 2 if I remove the require_matrix_t<M>* = nullptr then I get errors relevant to the content of the function, I’ll try to sort those out before another question…
edit 3 narrowing it down it requires two implementations for double and … something else, so now my user header looks like this
#include <stan/math.hpp>
#include <stan/math/rev/core/reverse_pass_callback.hpp>
namespace model_model_namespace {
using namespace stan;
using namespace std;
double usersum(const Eigen::MatrixXd& m, ostream *pstream__) {
return m.sum();
}
template <typename M>
promote_args_t<value_type_t<M>>
usersum(const M& m, ostream *pstream__) {
using value_t = value_type_t<M>;
using ret_type = promote_var_matrix_t<M,M>;
value_t ret(m.sum());
arena_t<Eigen::MatrixXd> one(m.rows(), m.cols());
one.fill(1.0);
arena_t<M> arena_m(m);
math::reverse_pass_callback([ret, arena_m, one]() mutable {
arena_m.adj() += one;
});
return ret;
}
}
(one is just a placeholder for an externally computed gradient) This compiles successfully.
edit 5 it seems value_t ret(m.sum()) is doing AD w/o being obvious and a value_of is required,
value_t ret(value_of(m).sum());
arena_t<M> arena_m(m);
math::reverse_pass_callback([ret, arena_m]() mutable {
arena_m.adj().array() += ret.adj();
});
This compiles and passes ./model diagnose.