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
.