Байесовский — Вызов подпрограмм Stan из программы на C ++

Я читаю Вот что можно (и я интерпретировал прямо) позвонить Стан подпрограммы из программы на C ++.

У меня есть несколько сложных функций логарифмического правдоподобия, которые я написал в C ++, и я действительно не представляю, как я могу их кодировать, используя язык Stan. Можно ли вызывать подпрограммы Монте-Карло в Stan, используя функцию правдоподобия, которую я уже написал в C ++? Если да, то есть ли примеры этого?

Это кажется вполне естественным, но я не могу найти ни примеров, ни указателей на то, как это сделать.

2

Решение

После дальнейшего рассмотрения (вы можете отказаться от моего предыдущего ответа), вы можете попробовать это: Напишите программу .stan с пользовательской функцией в functions блок, который имеет правильную подпись (и анализирует), но в основном ничего не делает. Как это

functions {
real foo_log(real[] y, vector beta, matrix X, real sigma) {
return not_a_number(); // replace this after parsing to C++
}
}
data {
int<lower=1> N;
int<lower=1> K;
matrix[N,K] X;
real y[N];
}
parameters {
vector[K] beta;
real<lower=0> sigma;
}
model {
y ~ foo(beta, X, sigma);
// priors here
}

Затем используйте CmdStan для компиляции этой модели, которая создаст файл .hpp в качестве промежуточного шага. Отредактируйте этот файл .hpp внутри тела foo_log вызвать вашу шаблонную функцию C ++, а также #include заголовочные файлы, в которых определены ваши вещи. Затем перекомпилируйте и выполните двоичный файл.

Это может на самом деле сработать для вас, но если то, что вы делаете, будет довольно полезным, мы будем рады, если вы внесете свой вклад в C ++.

2

Другие решения

Я думаю, что ваш вопрос немного отличается от того, с которым вы связаны. У него была полная программа Stan и он хотел вывести ее из C ++, тогда как вы спрашиваете, можете ли вы обойтись в написании программы Stan, вызвав внешнюю функцию C ++ для оценки вероятности записи в журнал. Но это не слишком далеко, потому что вам все равно придется передавать данные в форме, которую может обрабатывать Stan, объявлять Stan о неизвестных параметрах (плюс их поддержка) и т. Д. Итак, я не думаю, что вы можете (или должен) уклоняться от изучения языка Стэн.

Но довольно просто представить функцию C ++ для языка Stan, что, по сути, просто включает добавление файла my_loglikelihood.hpp в нужном месте под ${STAN_HOME}/lib/stan_math_${VERSION}/stan/math/добавление оператора включения в файл math.hpp в этом подкаталоге и редактирование ${STAN_HOME}/src/stan/lang/function_signatures.h, На этом этапе ваша программа .stan может выглядеть так же просто, как

data {
// declare data like y, X, etc.
}
parameters {
// declare parameters like theta
}
model {
// call y ~ my_logliklihood_log(theta, X)
}

Но я думаю, что реальный ответ на ваш вопрос заключается в том, что если вы уже написали функцию C ++ для оценки вероятности записи в журнал, то переписывание ее на языке Stan не должно занять более нескольких минут. Язык Stan очень похож на C, так что проще разобрать файл .stan в исходный файл C ++. Вот функция Стэна, которую я написал для логарифмической вероятности условно гауссовского результата в контексте регрессии:

functions {
/**
* Increments the log-posterior with the logarithm of a multivariate normal
* likelihood with a scalar standard deviation for all errors
* Equivalent to y ~ normal(intercept + X * beta, sigma) but faster
* @param beta vector of coefficients (excluding intercept)
* @param b precomputed vector of OLS coefficients (excluding intercept)
* @param middle matrix (excluding ones) typically precomputed as crossprod(X)
* @param intercept scalar (assuming X is centered)
* @param ybar precomputed sample mean of the outcome
* @param SSR positive precomputed value of the sum of squared OLS residuals
* @param sigma positive value for the standard deviation of the errors
* @param N integer equal to the number of observations
*/
void ll_mvn_ols_lp(vector beta, vector b, matrix middle,
real intercept, real ybar,
real SSR, real sigma, int N) {
increment_log_prob( -0.5 * (quad_form_sym(middle, beta - b) +
N * square(intercept - ybar) + SSR) /
square(sigma) - # 0.91... is log(sqrt(2 * pi()))
N * (log(sigma) + 0.91893853320467267) );
}
}

который в основном просто я сбрасываю то, что в противном случае может быть C-синтаксис в тело функции на языке Stan, которая затем вызывается в model блок программы .stan.

Короче говоря, я думаю, что вам, вероятно, будет проще переписать вашу функцию C ++ как функцию Stan. Тем не менее, возможно, что ваша логарифмическая вероятность включает в себя нечто экзотическое, для которого в настоящее время нет соответствующего синтаксиса Stan. В этом случае вы можете использовать эту функцию C ++ для языка Stan и в идеале отправлять запросы на извлечение данных в репозитории math и stan на GitHub под stan-dev, чтобы другие люди могли использовать ее (хотя тогда вам также придется написать юнит-тесты, документация и т. д.).

2