# External C++ Code with Precomputed Gradients

Hi everybody,

I’m trying to compile a model using an external C++ code with precomputed gradients in CmdStan following the examples of the PyStan and the RStan interfaces docs.

For that purpose, I’m using the following toy example:

• `external_grad.stan` file:
``````functions {
real my_func(real A, real B);
}
data {
real B;
}
parameters {
real A;
}
transformed parameters {
real C = my_func(A, B);
}
model {
C ~ std_normal();
}
``````
• `external_manual.hpp` file:
``````#include <cmath>
#include <ostream>
#include <stan/math.hpp>

using namespace stan::math;

inline double my_func (double A, double B, std::ostream* pstream) {
double C = A*B*B+A;

return C;
}

inline var my_func (const var& A_var, const var& B_var, std::ostream* pstream) {
// Compute the value
double A = A_var.val(),
B = B_var.val(),
C = my_func(A, B, pstream);

// Compute the partial derivatives:
double dC_dA = B*B+1.0,
dC_dB = 2.0*A*B;

// Autodiff wrapper:
return var(new precomp_vv_vari(
C,             // The _value_ of the output
A_var.vi_,     // The input gradient wrt A
B_var.vi_,     // The input gradient wrt B
dC_dA,         // The partial introduced by this function wrt A
dC_dB          // The partial introduced by this function wrt B
));
}

inline var my_func (double A, const var& B_var, std::ostream* pstream) {
double B = B_var.val(),
C = my_func(A, B, pstream),
dC_dB = 2.0*A*B;
return var(new precomp_v_vari(C, B_var.vi_, dC_dB));
}

inline var my_func (const var& A_var, double B, std::ostream* pstream) {
double A = A_var.val(),
C = my_func(A, B, pstream),
dC_dA = B*B+1.0;
return var(new precomp_v_vari(C, A_var.vi_, dC_dA));
}
}
``````

Unfortunately, the compilation throws the following error:

``````(stan-env) miguel@miguel-ASUS-Laptop-X407UBR:~/anaconda3/envs/stan-env/bin/cmdstan\$ make STANCFLAGS=--allow-undefined USER_HEADER=examples/external_grad/external_manual.hpp examples/external_grad/external_grad

--- Translating Stan model to C++ code ---

--- Compiling, linking C++ code ---
/home/miguel/anaconda3/envs/stan-env/bin/x86_64-conda-linux-gnu-c++ -fvisibility-inlines-hidden -std=c++17 -fmessage-length=0 -march=nocona -mtune=haswell -ftree-vectorize -fPIC -fstack-protector-strong -fno-plt -O2 -ffunction-sections -pipe -isystem /home/miguel/anaconda3/envs/stan-env/include -std=c++1y -D_REENTRANT -Wno-sign-compare -Wno-ignored-attributes      -I /home/miguel/anaconda3/envs/stan-env/include/    -O3 -I src -I stan/src -I lib/rapidjson_1.1.0/ -I lib/CLI11-1.9.1/ -I stan/lib/stan_math/ -I stan/lib/stan_math/lib/eigen_3.3.9 -I stan/lib/stan_math/lib/boost_1.75.0 -I stan/lib/stan_math/lib/sundials_5.7.0/include -DNDEBUG -D_FORTIFY_SOURCE=2 -O2 -isystem /home/miguel/anaconda3/envs/stan-env/include    -DBOOST_DISABLE_ASSERTS   -DTBB_INTERFACE_NEW  -DTBB_INTERFACE_NEW     -c -include examples/external_grad/external_manual.hpp -x c++ -o examples/external_grad/external_grad.o examples/external_grad/external_grad.hpp
In file included from <command-line>:
./examples/external_grad/external_manual.hpp:39:14: error: expected primary-expression before '(' token
39 |    return var(new precomp_v_vari(C, B_var.vi_, dC_dB));
|              ^
./examples/external_grad/external_manual.hpp:39:19: error: expected type-specifier before 'precomp_v_vari'
39 |    return var(new precomp_v_vari(C, B_var.vi_, dC_dB));
|                   ^~~~~~~~~~~~~~
./examples/external_grad/external_manual.hpp:46:14: error: expected primary-expression before '(' token
46 |    return var(new precomp_v_vari(C, A_var.vi_, dC_dA));
|              ^
./examples/external_grad/external_manual.hpp:46:19: error: expected type-specifier before 'precomp_v_vari'
46 |    return var(new precomp_v_vari(C, A_var.vi_, dC_dA));
|                   ^~~~~~~~~~~~~~
``````

It seems that the `precomp_v_vari` class is not founded. By checking the Stan Math Library docs, I’m not able to found that class either, I only found the precomp_vv_vari class.

So my question is, what is the correct way to compile my model in CmdStan?

• Operating System: Ubuntu 18
• CmdStan Version: 2.28.2
• Compiler/Toolkit: g++ 7.5.0
1 Like

Hi Miguel, Stan now uses the `make_callback_var` function to specify pre-computed gradients, I put together an example of using this for pre-computed gradients over in this post: Gamma distribution quantile and inverse quantile function - #42 by andrjohns

2 Likes

So, according to your example, I just need to remove the functions:

``````inline var my_func (double A, const var& B_var, std::ostream* pstream);
inline var my_func (const var& A_var, double B, std::ostream* pstream);
``````

keeping only the function that has all the parameters as `var` inputs:

``````inline var my_func (const var& A_var, const var& B_var, std::ostream* pstream);
``````

Is that correct?

No, you still keep the same number of function definitions, you just use `make_callback_var` instead of `precomp_v_vari`

My model now compiles with no errors, thank you!

I’m attaching the corrected code of my toy example based on @andrjohns’s suggestions for anyone stuck on the same error.

• `external_manual.hpp` file (corrected):
``````#include <ostream>
#include <stan/math/rev/core.hpp>

using namespace stan::math;

inline double my_func(double A, double B, std::ostream* pstream) {
return A * B * B + A;
}

inline var my_func (const var& A_var, const var& B_var, std::ostream* pstream) {
// Extract values from inputs
double A = A_var.val();
double B = B_var.val();
double C = my_func(A, B, pstream);
// Compute the partial derivatives
double dC_dA = B * B + 1.0;
double dC_dB = 2.0 * A * B;
// Return the new parameter with values of the function and gradients
return make_callback_var(C, [A_var, B_var, dC_dA, dC_dB](auto& vi) {
});
}

inline var my_func(double A, const var& B_var, std::ostream* pstream) {
// Extract values from inputs
double B = B_var.val();
double C = my_func(A, B, pstream);
// Compute the partial derivatives
double dC_dB = 2.0 * A * B;
// Return the new parameter with values of the function and gradients
return make_callback_var(C, [B_var, dC_dB](auto& vi) {
});
}

inline var my_func(const var& A_var, double B, std::ostream* pstream) {
// Extract values from inputs
double A = A_var.val();
double C = my_func(A, B, pstream);
// Compute the partial derivatives
double dC_dA = B * B + 1.0;
// Return the new parameter with values of the function and gradients
return make_callback_var(C, [A_var, dC_dA](auto& vi) {