laplace_marginal_tol with integrate_1d inside likelihood doesn't compile

Đang mở
#3,280 12 bình luận 0 reaction 1 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@SteveBronder đang làm issue này rồi.

Từ ngày 12/2/2026.

Đánh giá

Issue này chưa được đánh giá.

Mô tả

Not a minimal example, but maybe the reason is obvious anyway? If laplace_marginal_tol likelihood function has integrate_1d inside, the C++ compilation fails. I'm fine if that is not supported, but then it would be good to check that before C++ compilation and report that it's not supported

Errror is quite long, so here only the end

/tmp/RtmpGPlDrK/model-12448b780d70f3.hpp:1504:43:   required from here
stan/lib/stan_math/stan/
math/rev/functor/integrate_1d.hpp:128:29: error: no match for call to ‘(const integrate_1d_adapter<disc_golf_base_nonconst_angle2_dist2_hier_error_la_model_namespace::integrand_functor__>) (const double&, const double&, std::ostream* const&, std::vector<stan::math::var_value<double>, std::allocator<stan::math::var_value<double> > >&, std::vector<stan::math::var_value<double>, std::allocator<stan::math::var_value<double> > >&, std::vector<stan::math::var_value<double>, std::allocator<stan::math::var_value<double> > >&)’
  128 |                     return f(x, xc, msgs, local_args...);
      |                            ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from stan/lib/stan_math/stan/math/prim/functor/integrate_1d.hpp:7,
                 from stan/lib/stan_math/stan/math/prim/functor/hcubature.hpp:27,
                 from stan/lib/stan_math/stan/math/prim/functor.hpp:14,
                 from stan/lib/stan_math/stan/math/rev/fun/to_arena.hpp:7,
                 from stan/lib/stan_math/stan/math/rev/core/operator_division.hpp:15,
                 from stan/lib/stan_math/stan/math/rev/core/operator_divide_equal.hpp:5,
                 from stan/lib/stan_math/stan/math/rev/core.hpp:32,
                 from stan/lib/stan_math/stan/math/mix/meta.hpp:6,
                 from stan/lib/stan_math/stan/math/mix.hpp:8,
                 from /tmp/RtmpGPlDrK/model-12448b780d70f3.hpp:3:
stan/lib/stan_math/stan/math/prim/functor/integrate_1d_adapter.hpp:20:8: note: candidate: ‘template<class T_a, class T_b, class T_theta> auto integrate_1d_adapter<F>::operator()(const T_a&, const T_b&, std::ostream*, const std::vector<T_theta>&, const std::vector<double, std::allocator<double> >&, const std::vector<int>&) const [with T_a = T_a; T_b = T_b; T_theta = T_theta; F = disc_golf_base_nonconst_angle2_dist2_hier_error_la_model_namespace::integrand_functor__]’
   20 |   auto operator()(const T_a& x, const T_b& xc, std::ostream* msgs,
      |        ^~~~~~~~
stan/lib/stan_math/stan
/math/prim/functor/integrate_1d_adapter.hpp:20:8: note:   template argument deduction/substitution failed:
In file included from stan/lib/stan_math/stan/math/rev/functor.hpp:15,
                 from stan/lib/stan_math/stan/math/mix/functor/wolfe_line_search.hpp:10,
                 from stan/lib/stan_math/stan/math/mix/functor/laplace_marginal_density_estimator.hpp:5,
                 from stan/lib/stan_math/stan/math/mix/functor/laplace_marginal_density.hpp:5,
                 from stan/lib/stan_math/stan/math/mix/functor/laplace_base_rng.hpp:5,
                 from stan/lib/stan_math/stan/math/mix/functor.hpp:11,
                 from stan/lib/stan_math/stan/math/mix.hpp:10,
                 from /tmp/RtmpGPlDrK/model-12448b780d70f3.hpp:3:
stan/lib/stan_math/stan/math/rev/functor/integrate_1d.hpp:128:29: note:   cannot convert ‘local_args#1’ (type ‘std::vector<stan::math::var_value<double>, std::allocator<stan::math::var_value<double> > >’) to type ‘const std::vector<double, std::allocator<double> >&’
  128 |                     return f(x, xc, msgs, local_args...);
      |                            ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~

make: *** [make/program:77: /tmp/RtmpGPlDrK/model-12448b780d70f3.o] Error 1

And the Stan model code causing that error

// Disc golf putting model with 2D angular uncertainty and distance uncertainty
// Hierarchical version with player-level effects for sigma_angle_base, sigma_angle_slope, sigma_distance
functions {
  real integrand(real z, real notused, array[] real theta,
               array[] real X_j, array[] int data_j) {
    real sigma_epsilon = theta[1];
    real p_j = theta[2];
    int n_j = data_j[1];
    int y_j = data_j[2];
    real p = (z<1) ? exp(gamma_lpdf(z | 1, 1/sigma_epsilon) + binomial_lpmf(y_j | n_j, p_j*(1-z))) : 0;
    return (is_inf(p) || is_nan(p)) ? 0 : p;
  }

  // Log-likelihood function for a single player (group)
  // theta = [eta_1, eta_2, eta_3] (player-level effects on log scale)
  // Data tuple contains player-specific observations
  real player_group_ll(vector theta,
                       int n_g, array[] int y_g, array[] int n_attempts_g,
                       vector x_g, vector threshold_angle_g,
                       real sigma_base, real threshold_distance,
                       real sigma_epsilon, real R_val) {
    real sigma_angle_base_p = exp(theta[1]);
    real sigma_angle_slope_p = exp(theta[2]);
    real sigma_distance_p = exp(theta[3]);
    real p_base = Phi(1.0 / sigma_base);
    real ll = 0;
    for (i in 1:n_g) {
      real sigma_angle = sqrt(square(sigma_angle_base_p) + square(sigma_angle_slope_p * x_g[i]));
      real p_angle = rayleigh_cdf(threshold_angle_g[i] | sigma_angle);
      real p_distance;
      if (x_g[i] <= threshold_distance) {
        p_distance = 1.0;
      } else {
        p_distance = normal_cdf(1.0 | 0.0, sigma_distance_p * (x_g[i] - threshold_distance));
      }
      real pr_i = p_base * p_angle * p_distance;
      // Integrate out epsilon for this observation
      ll += log(integrate_1d(integrand,
                             0,
                             positive_infinity(),
                             append_array({sigma_epsilon}, {pr_i}),
                             {0},
                             append_array({n_attempts_g[i]}, {y_g[i]}),
                             1e-9));
    }
    return ll;
  }

  // Covariance function for player-level effects
  matrix cov_group(vector tau_v, matrix L_Omega_v) {
    return multiply_lower_tri_self_transpose(diag_pre_multiply(tau_v, L_Omega_v));
  }
}
data {
  int N_obs;
  int N_players;
  vector[N_obs] x;              // distance in feet
  array[N_obs] int n;           // number of attempts
  array[N_obs] int y;           // number of successes
  array[N_obs] int player;      // player index
  real R;                       // target radius (half of basket diameter)
}
transformed data {
  // Maximum allowable angle at each distance
  vector[N_obs] threshold_angle = asin(R ./ x);
  int K = 3;  // number of player-level parameters (sigma_angle_base, sigma_angle_slope, sigma_distance)

  // Prepare player-specific data arrays for Laplace approximation
  array[N_players] int n_pg;  // number of observations per player
  array[N_players, N_obs] int y_pg;  // y values per player (padded)
  array[N_players, N_obs] int n_attempts_pg;  // n values per player (padded)
  array[N_players, N_obs] real x_pg_arr;  // x values per player (padded)
  array[N_players, N_obs] real threshold_angle_pg_arr;  // threshold_angle per player (padded)

  // initialize counts
  for (p in 1:N_players) {
    n_pg[p] = 0;
  }
  // populate player-specific arrays
  for (j in 1:N_obs) {
    int p = player[j];
    n_pg[p] += 1;
    y_pg[p, n_pg[p]] = y[j];
    n_attempts_pg[p, n_pg[p]] = n[j];
    x_pg_arr[p, n_pg[p]] = x[j];
    threshold_angle_pg_arr[p, n_pg[p]] = threshold_angle[j];
  }

  // Control parameters for Laplace approximation
  real la_tolerance = 1e-4;
  int la_max_num_steps = 100, la_hessian_block_size = 3, la_solver = 2, la_max_steps_line_search = 100;
}
parameters {
  // Population-level parameters (on log scale for positive constraint)
  vector[K] mu;                     // population means
  vector<lower=0>[K] tau;           // population SDs
  cholesky_factor_corr[K] L_Omega;  // Cholesky factor of correlation matrix
  
  // Non-centered player effects (standard normal)
  matrix[K, N_players] z;
  
  // Pooled parameters
  real<lower=0> sigma_base;         // base angular precision (radians)
  real<lower=0> threshold_distance; // distance threshold
  real<lower=0> sigma_epsilon;
  vector<lower=0, upper=1>[N_obs] epsilon;
}
transformed parameters {
  // Player-level parameters (on log scale)
  matrix[N_players, K] eta;
  
  // Transform from non-centered to centered parameterization
  // eta = mu + diag(tau) * L_Omega * z
  eta = (diag_pre_multiply(tau, L_Omega) * z)';
  for (p in 1:N_players) {
    eta[p] = eta[p] + mu';
  }
  
  // Player-level parameters on natural scale
  vector<lower=0>[N_players] sigma_angle_base;
  vector<lower=0>[N_players] sigma_angle_slope;
  vector<lower=0>[N_players] sigma_distance;
  for (p in 1:N_players) {
    sigma_angle_base[p] = exp(eta[p, 1]);
    sigma_angle_slope[p] = exp(eta[p, 2]);
    sigma_distance[p] = exp(eta[p, 3]);
  }
  
  // Observation-level probabilities
  vector[N_obs] pr;
  for (j in 1:N_obs) {
    int pl = player[j];
    // base probability
    real p_base = Phi(1.0 / sigma_base);
    // probability of correct angle (distance-dependent SD)
    real sigma_angle = sqrt(square(sigma_angle_base[pl]) + square(sigma_angle_slope[pl] * x[j]));
    real p_angle = rayleigh_cdf(threshold_angle[j] | sigma_angle);
    // probability of correct distance
    real p_distance;
    if (x[j] <= threshold_distance) {
      p_distance = 1.0;
    } else {
      p_distance = normal_cdf(1.0 | 0.0, sigma_distance[pl] * (x[j] - threshold_distance));
    }
    // combined probability assuming independence
    pr[j] = p_base * p_angle * p_distance;
  }
}
model {
  // priors on population parameters
  mu[1] ~ normal(-6, 2);            // prior for mean log_sigma_angle_base
  mu[2] ~ normal(-6, 2);            // prior for mean log_sigma_angle_slope
  mu[3] ~ normal(-6, 2);            // prior for mean log_sigma_distance
  tau[1] ~ normal(0, 0.5);            // population SDs
  tau[2] ~ normal(0, 0.5);            // population SDs
  tau[3] ~ normal(0, 0.5);            // population SDs
  L_Omega ~ lkj_corr_cholesky(3);  // LKJ prior on correlation
  
  // non-centered parameterization: z ~ normal(0, 1)
  to_vector(z) ~ std_normal();
  
  // priors on pooled parameters
  sigma_base ~ normal(0, 1);
  threshold_distance ~ normal(40, 10);

  epsilon ~ gamma(1, 1/sigma_epsilon);

  // data model
  y ~ binomial(n, pr .* (1 - epsilon));
}
generated quantities {
  vector[N_obs] p = pr .* (1 - gamma_rng(1, 1/sigma_epsilon));
  vector[N_obs] log_lik;
  vector[N_obs] log_liki;
  for (j in 1:N_obs) {
    log_lik[j] = binomial_lpmf(y[j] | n[j], pr[j] * (1 - epsilon[j]));
    log_liki[j] = log(integrate_1d(integrand,
                              0,
                              positive_infinity(), // this works better than 1!
                              append_array({sigma_epsilon}, {pr[j]}),
			      {0}, // not used, but an empty array not allowed
			      append_array({n[j]}, {y[j]}),
			      1e-9));
  }
  // Player-level log-likelihoods using Laplace approximation
  vector[N_players] log_lik_g;
  for (g in 1:N_players) {
    vector[N_obs] x_pg_vec = to_vector(x_pg_arr[g]);
    vector[N_obs] threshold_angle_pg_vec = to_vector(threshold_angle_pg_arr[g]);

    // Use sampled player effects as starting point for Newton solver
    vector[K] theta_init = eta[g]';

    log_lik_g[g] = laplace_marginal_tol(player_group_ll,
                                     (n_pg[g], y_pg[g], n_attempts_pg[g],
                                      x_pg_vec, threshold_angle_pg_vec,
                                      sigma_base, threshold_distance,
                                      sigma_epsilon, R),
                                     cov_group, (tau, L_Omega),
                                     (theta_init, la_tolerance, la_max_num_steps,
                                      la_hessian_block_size, la_solver, la_max_steps_line_search, 1));
  }

  vector[N_players] p33;
  for (j in 1:N_players) {
    real x33 = 33;
    real threshold_angle33 = asin(R ./ x33);
    int pl = j;
    // base probability
    real p_base = Phi(1.0 / sigma_base);
    // probability of correct angle (distance-dependent SD)
    real sigma_angle = sqrt(square(sigma_angle_base[pl]) + square(sigma_angle_slope[pl] * x33));
    real p_angle = rayleigh_cdf(threshold_angle33 | sigma_angle);
    // probability of correct distance
    real p_distance;
    if (x33 <= threshold_distance) {
      p_distance = 1.0;
    } else {
      p_distance = normal_cdf(1.0 | 0.0, sigma_distance[pl] * (x33 - threshold_distance));
    }
    // combined probability assuming independence
    p33[pl] = p_base * p_angle * p_distance .* (1 - gamma_rng(1, 1/sigma_epsilon));
  }
}
Ngôn ngữ chính
C++
Star
845
Fork
225
Merge trung bình
3 ngày 9 giờ
Pull request đã merge (30 ngày)
12

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của stan-dev/math

Tất cả issue của stan-dev/math

Issue tương tự

Thêm issue về C++

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.