Converting Stan data types to C/C++ primative types

Hello all,

Thanks to @WardBrian’s help on a previous post, I was able to connect an external header file to my Stan model during compilation with Cmdstan.

However, I am running into an issue when trying to integrate my C++ code into the external header file. Namely, if I try to do a basic instantiation such as double test = value where value is defined using the following Stan generated template code…

#include <stan/model/model_header.hpp>
#include <ostream>

namespace _namespace {

template <typename T0__, stan::require_stan_scalar_t<T0__>* = nullptr>
stan::promote_args_t<T0__>
external_function(const T0__& value, std::ostream* pstream__)
{
    double test = value; 

    return test; 
}
}

… I run into the following error:

./examples/code/external_code.hpp:26:12: error: cannot convert 
‘const stan::math::var_value<double>’ to ‘double’ in initialization 
double test = value;

I figured there are three solutions in this case:

  1. Develop my external C++ code using the Stan-math data types.
  2. Convert the values coming from the Stan model into C++ primitive data types, do X amount of work with these converted values, and then convert them back to Stan-math data types upon returning.
  3. A mixture of both solutions.

While the second solution feels tedious, I feel like the first solution is limiting.

As such, unless it is strongly recommended I go with the first solution, my question: Is there a way to convert the data types used in Stan’s math library into C/C++ primitive data types? And then back again?

  • Operating System: Ubuntu 20.04 amd64
  • CmdStan Version: v2.29.2
  • Compiler/Toolkit: g++ 9.4.0 and make 4.2.1

Thank you for any help you can offer.

-Matt

1 Like

The key thing to remember with this type of C++ is that it’s templated to accept multiple types, so you have to adjust your own code accordingly.

In your function, T0__ is used to represent the scalar type of the inputs (double if the function is called with doubles or var if called with var. So you just need to change your test declaration to:

template <typename T0__, stan::require_stan_scalar_t<T0__>* = nullptr>
stan::promote_args_t<T0__>
external_function(const T0__& value, std::ostream* pstream__)
{
    T0__ test = value; 

    return test; 
}
1 Like

Thank you for your help, @andrjohns!

If I wanted to use something like C++'s standard exp() function, I couldn’t use the one supplied in math.h directly. Instead, I would need to use the one within Stan’s math library since it is templated appropriately or create my own templated version. Is that correct?

Yep, that’s right. However, if you want specify custom gradients or use functions from another c++ library (which Stan can’t always auto-differentiate), then you’ll need to create separate overloads for double and var inputs.

You can use the Math definitions of the Phi function as simple examples for how this would look:

double overload

var overload

1 Like

And for a more complex “production” example, this post shows the overloads needed for exposing a function from the Boost math library with custom gradients: Gamma distribution quantile and inverse quantile function - #40 by andrjohns

1 Like