diff --git a/src/frontend/Semantic_error.ml b/src/frontend/Semantic_error.ml index 96b9f8e72..d31ba7374 100644 --- a/src/frontend/Semantic_error.ml +++ b/src/frontend/Semantic_error.ml @@ -69,6 +69,7 @@ module TypeError = struct | IlltypedLaplaceHessianBlockSize of string * (UnsizedType.autodifftype * UnsizedType.t) option | IlltypedLaplaceTolArgs of string * SignatureMismatch.function_mismatch + | IlltypedLaplaceLatentSolveArgs of string | AmbiguousFunctionPromotion of string * UnsizedType.t list option @@ -328,6 +329,11 @@ module TypeError = struct Fmt.pf ppf "@[The %s to %a@ must be@ %a.%a@]" (laplace_tolerance_arg_name n) quoted name expected_types [expected] found_type found + | IlltypedLaplaceLatentSolveArgs name -> + Fmt.pf ppf + "@[All arguments to %a must be a data-only@ if used outside the \ + generated quantities@ block.@ %a@]" + quoted name SignatureMismatch.data_only_msg () | AmbiguousFunctionPromotion (name, arg_tys, signatures) -> let pp_sig ppf (rt, args, _) = Fmt.pf ppf "@[(@[%a@]) => %a@]" @@ -892,6 +898,9 @@ let illtyped_laplace_hessian_block_size_arg loc name arg_ty = let illtyped_laplace_tolerance_args loc name mismatch = (loc, TypeError (TypeError.IlltypedLaplaceTolArgs (name, mismatch))) +let illtyped_laplace_latent_solve_args loc name = + (loc, TypeError (TypeError.IlltypedLaplaceLatentSolveArgs name)) + let ambiguous_function_promotion loc name arg_tys signatures = ( loc , TypeError (TypeError.AmbiguousFunctionPromotion (name, arg_tys, signatures)) diff --git a/src/frontend/Semantic_error.mli b/src/frontend/Semantic_error.mli index 354d1558f..817baaa30 100644 --- a/src/frontend/Semantic_error.mli +++ b/src/frontend/Semantic_error.mli @@ -125,6 +125,8 @@ val illtyped_laplace_hessian_block_size_arg : val illtyped_laplace_tolerance_args : Location_span.t -> string -> SignatureMismatch.function_mismatch -> t +val illtyped_laplace_latent_solve_args : Location_span.t -> string -> t + val nonreturning_fn_expected_returning_found : Location_span.t -> string -> Location_span.t option -> t diff --git a/src/frontend/Typechecker.ml b/src/frontend/Typechecker.ml index b3e22402d..5da35b5b3 100644 --- a/src/frontend/Typechecker.ml +++ b/src/frontend/Typechecker.ml @@ -497,6 +497,10 @@ let verify_fn_rng cf loc id = || cf.current_block = TData) then Semantic_error.invalid_rng_fn loc |> error +let is_laplace_latent_solve name = + Stan_math_signatures.is_embedded_laplace_fn name + && String.is_substring name ~substring:"_solve" + let mk_fun_app ~is_cond_dist ~loc kind name args ~type_ : Ast.typed_expression = let fn = if is_cond_dist then CondDistApp (kind, name, args) @@ -877,6 +881,15 @@ and check_laplace_fn ~is_cond_dist loc cf tenv id tes = else (* likelihood callback check *) match tes with + | _ :: {emeta= {ad_level; loc; _}; expr} :: _ + when is_laplace_latent_solve id.name + && UnsizedType.is_autodifftype ad_level -> + let es = match expr with TupleExpr es -> es | _ -> [] in + let loc = + List.find_map es ~f:(fun {emeta= {loc; ad_level; _}; _} -> + Option.some_if (UnsizedType.is_autodifftype ad_level) loc) + |> Option.value ~default:loc in + Semantic_error.illtyped_laplace_latent_solve_args loc id.name |> error | {expr= Variable lik_fun; _} :: lik_tupl :: tes -> let lik_fun, lik_tupl = (* adds the function name to the global list that is checked @@ -907,6 +920,15 @@ and check_laplace_fn ~is_cond_dist loc cf tenv id tes = |> error in (* Check the remaining arguments: initial guess, covariance, and tolerances *) match rest with + | _ :: {emeta= {ad_level; loc; _}; expr} :: _ + when is_laplace_latent_solve id.name && UnsizedType.is_autodifftype ad_level + -> + let es = match expr with TupleExpr es -> es | _ -> [] in + let loc = + List.find_map es ~f:(fun {emeta= {loc; ad_level; _}; _} -> + Option.some_if (UnsizedType.is_autodifftype ad_level) loc) + |> Option.value ~default:loc in + Semantic_error.illtyped_laplace_latent_solve_args loc id.name |> error | {expr= Variable cov_fun; _} :: cov_tupl :: control_args -> let cov_fun_type, cov_tupl = check_function_callable_with_tuple cf tenv id cov_fun cov_tupl @@ -920,6 +942,8 @@ and check_laplace_fn ~is_cond_dist loc cf tenv id tes = lik_args @ (hbs_arg :: cov_fun_type :: cov_tupl :: control_args) in let return_type = if String.is_suffix id.name ~suffix:"_rng" then UnsizedType.UVector + else if String.is_substring id.name ~substring:"_solve" then + UnsizedType.UTuple [UVector; UMatrix] else UnsizedType.UReal in mk_fun_app ~is_cond_dist ~loc (StanLib (Fun_kind.suffix_from_name id.name)) diff --git a/src/stan_math_signatures/Stan_math_signatures.ml b/src/stan_math_signatures/Stan_math_signatures.ml index 49dedc2d9..c21409acc 100644 --- a/src/stan_math_signatures/Stan_math_signatures.ml +++ b/src/stan_math_signatures/Stan_math_signatures.ml @@ -153,7 +153,8 @@ let is_reduce_sum_fn f = let embedded_laplace_functions = [ (* general fns *) "laplace_marginal"; "laplace_marginal_tol" - ; "laplace_latent_rng"; "laplace_latent_tol_rng"; (* "helpers" *) + ; "laplace_latent_rng"; "laplace_latent_tol_rng"; "laplace_latent_solve" + ; "laplace_latent_solve_tol"; (* "helpers" *) "laplace_marginal_bernoulli_logit_lpmf" ; "laplace_marginal_tol_bernoulli_logit_lpmf" ; "laplace_marginal_neg_binomial_2_log_lpmf" diff --git a/test/integration/bad/embedded_laplace/bad_solve_cov.stan b/test/integration/bad/embedded_laplace/bad_solve_cov.stan new file mode 100644 index 000000000..da7391f63 --- /dev/null +++ b/test/integration/bad/embedded_laplace/bad_solve_cov.stan @@ -0,0 +1,40 @@ +functions { + // specify negative binomial likelihood with mean offset + real ll_function(vector theta, // latent Gaussian + real eta, vector log_ye, // mean offset + array[] int y) { + // observed count + return neg_binomial_2_lpmf(y | exp(log_ye + theta), eta); + } + + // specify covariance function + matrix K_function(array[] vector x, int n_obs, real alpha, real rho) { + matrix[n_obs, n_obs] K = gp_exp_quad_cov(x, alpha, rho); + for (i in 1 : n_obs) + K[i, i] += 1e-8; + return K; + } +} +data { + int n_obs; + int n_coordinates; + array[n_obs] int y; + vector[n_obs] ye; + array[n_obs] vector[n_coordinates] x; +} + +transformed data { + vector[n_obs] log_ye = log(ye); +} +parameters { + real alpha; + real rho; + real eta; +} + +model { + // laplace_latent_solve is only callable in Generated Quantities block + tuple(vector[n_obs], matrix[n_obs, n_obs]) mean_chol + = laplace_latent_solve(ll_function, (1.0, log_ye, y), 1, + K_function, (x, n_obs, alpha, rho)); +} \ No newline at end of file diff --git a/test/integration/bad/embedded_laplace/bad_solve_lik.stan b/test/integration/bad/embedded_laplace/bad_solve_lik.stan new file mode 100644 index 000000000..3474c58c7 --- /dev/null +++ b/test/integration/bad/embedded_laplace/bad_solve_lik.stan @@ -0,0 +1,40 @@ +functions { + // specify negative binomial likelihood with mean offset + real ll_function(vector theta, // latent Gaussian + real eta, vector log_ye, // mean offset + array[] int y) { + // observed count + return neg_binomial_2_lpmf(y | exp(log_ye + theta), eta); + } + + // specify covariance function + matrix K_function(array[] vector x, int n_obs, real alpha, real rho) { + matrix[n_obs, n_obs] K = gp_exp_quad_cov(x, alpha, rho); + for (i in 1 : n_obs) + K[i, i] += 1e-8; + return K; + } +} +data { + int n_obs; + int n_coordinates; + array[n_obs] int y; + vector[n_obs] ye; + array[n_obs] vector[n_coordinates] x; +} + +transformed data { + vector[n_obs] log_ye = log(ye); +} +parameters { + real alpha; + real rho; + real eta; +} + +model { + // laplace_latent_solve is only callable in Generated Quantities block + tuple(vector[n_obs], matrix[n_obs, n_obs]) mean_chol + = laplace_latent_solve(ll_function, (eta, log_ye, y), 1, + K_function, (x, n_obs, alpha, rho)); +} diff --git a/test/integration/bad/embedded_laplace/bad_solve_tol.stan b/test/integration/bad/embedded_laplace/bad_solve_tol.stan new file mode 100644 index 000000000..fbec3ff86 --- /dev/null +++ b/test/integration/bad/embedded_laplace/bad_solve_tol.stan @@ -0,0 +1,40 @@ +functions { + // specify negative binomial likelihood with mean offset + real ll_function(vector theta, // latent Gaussian + real eta, vector log_ye, // mean offset + array[] int y) { + // observed count + return neg_binomial_2_lpmf(y | exp(log_ye + theta), eta); + } + + // specify covariance function + matrix K_function(array[] vector x, int n_obs, real alpha, real rho) { + matrix[n_obs, n_obs] K = gp_exp_quad_cov(x, alpha, rho); + for (i in 1 : n_obs) + K[i, i] += 1e-8; + return K; + } +} +data { + int n_obs; + int n_coordinates; + array[n_obs] int y; + vector[n_obs] ye; + array[n_obs] vector[n_coordinates] x; +} + +transformed data { + vector[n_obs] log_ye = log(ye); +} +parameters { + real alpha; + real rho; + real eta; +} + +generated quantities { + // _tol variant requires a trailing control-parameter tuple + tuple(vector[n_obs], matrix[n_obs, n_obs]) mean_chol + = laplace_latent_solve_tol(ll_function, (eta, log_ye, y), 1, K_function, + (x, n_obs, alpha, rho)); +} diff --git a/test/integration/bad/embedded_laplace/stanc.expected b/test/integration/bad/embedded_laplace/stanc.expected index 99aa7728e..12a256ff6 100644 --- a/test/integration/bad/embedded_laplace/stanc.expected +++ b/test/integration/bad/embedded_laplace/stanc.expected @@ -325,6 +325,51 @@ Semantic error in 'bad_overload.stan', line 2, column 7 to column 51: ------------------------------------------------- Identifier "laplace_marginal_tol_neg_binomial_2_log_lpmf" clashes with a non-overloadable Stan Math library function. +[exit 1] + $ stanc bad_solve_cov.stan +Semantic error in 'bad_solve_cov.stan', line 39, column 52 to column 57: + ------------------------------------------------- + 37: tuple(vector[n_obs], matrix[n_obs, n_obs]) mean_chol + 38: = laplace_latent_solve(ll_function, (1.0, log_ye, y), 1, + 39: K_function, (x, n_obs, alpha, rho)); + ^ + 40: } + ------------------------------------------------- + +All arguments to "laplace_latent_solve" must be a data-only +if used outside the generated quantities block. (Local variables are assumed +to depend on parameters; same goes for function inputs unless they are marked +with the keyword "data".) +[exit 1] + $ stanc bad_solve_lik.stan +Semantic error in 'bad_solve_lik.stan', line 38, column 43 to column 46: + ------------------------------------------------- + 36: // laplace_latent_solve is only callable in Generated Quantities block + 37: tuple(vector[n_obs], matrix[n_obs, n_obs]) mean_chol + 38: = laplace_latent_solve(ll_function, (eta, log_ye, y), 1, + ^ + 39: K_function, (x, n_obs, alpha, rho)); + 40: } + ------------------------------------------------- + +All arguments to "laplace_latent_solve" must be a data-only +if used outside the generated quantities block. (Local variables are assumed +to depend on parameters; same goes for function inputs unless they are marked +with the keyword "data".) +[exit 1] + $ stanc bad_solve_tol.stan +Semantic error in 'bad_solve_tol.stan', line 38, column 8 to line 39, column 56: + ------------------------------------------------- + 36: // _tol variant requires a trailing control-parameter tuple + 37: tuple(vector[n_obs], matrix[n_obs, n_obs]) mean_chol + 38: = laplace_latent_solve_tol(ll_function, (eta, log_ye, y), 1, K_function, + ^ + 39: (x, n_obs, alpha, rho)); + 40: } + ------------------------------------------------- + +Missing control parameter tuple at the end of the call to "laplace_latent_solve_tol". +Expected a tuple of 6 arguments for the control parameters. [exit 1] $ stanc bad_theta0.stan Semantic error in 'bad_theta0.stan', line 43, column 9 to column 16: diff --git a/test/integration/good/code-gen/cpp.expected b/test/integration/good/code-gen/cpp.expected index a8f7b8ebf..c91d0048b 100644 --- a/test/integration/good/code-gen/cpp.expected +++ b/test/integration/good/code-gen/cpp.expected @@ -7952,18 +7952,28 @@ namespace laplace_functionals_model_namespace { using stan::model::model_base_crtp; using namespace stan::math; stan::math::profile_map profiles__; -static constexpr std::array locations_array__ = +static constexpr std::array locations_array__ = {" (found before start of program)", " (in 'laplace_functionals.stan', line 43, column 2 to column 22)", " (in 'laplace_functionals.stan', line 44, column 2 to column 20)", " (in 'laplace_functionals.stan', line 45, column 2 to column 20)", - " (in 'laplace_functionals.stan', line 62, column 2 to line 64, column 67)", - " (in 'laplace_functionals.stan', line 66, column 2 to line 72, column 99)", + " (in 'laplace_functionals.stan', line 72, column 2 to line 74, column 67)", + " (in 'laplace_functionals.stan', line 76, column 2 to line 82, column 99)", + " (in 'laplace_functionals.stan', line 84, column 2 to line 86, column 65)", + " (in 'laplace_functionals.stan', line 88, column 2 to line 93, column 77)", " (in 'laplace_functionals.stan', line 48, column 2 to column 55)", " (in 'laplace_functionals.stan', line 49, column 2 to column 61)", " (in 'laplace_functionals.stan', line 50, column 2 to column 21)", " (in 'laplace_functionals.stan', line 52, column 2 to line 53, column 65)", " (in 'laplace_functionals.stan', line 55, column 2 to line 58, column 83)", + " (in 'laplace_functionals.stan', line 60, column 15 to column 20)", + " (in 'laplace_functionals.stan', line 60, column 30 to column 35)", + " (in 'laplace_functionals.stan', line 60, column 37 to column 42)", + " (in 'laplace_functionals.stan', line 60, column 2 to line 62, column 63)", + " (in 'laplace_functionals.stan', line 64, column 15 to column 20)", + " (in 'laplace_functionals.stan', line 64, column 30 to column 35)", + " (in 'laplace_functionals.stan', line 64, column 37 to column 42)", + " (in 'laplace_functionals.stan', line 64, column 2 to line 69, column 77)", " (in 'laplace_functionals.stan', line 19, column 2 to column 12)", " (in 'laplace_functionals.stan', line 20, column 2 to column 20)", " (in 'laplace_functionals.stan', line 21, column 8 to column 13)", @@ -7987,8 +7997,14 @@ static constexpr std::array locations_array__ = " (in 'laplace_functionals.stan', line 38, column 2 to column 17)", " (in 'laplace_functionals.stan', line 39, column 2 to column 32)", " (in 'laplace_functionals.stan', line 40, column 2 to column 28)", - " (in 'laplace_functionals.stan', line 62, column 9 to column 14)", - " (in 'laplace_functionals.stan', line 66, column 9 to column 14)", + " (in 'laplace_functionals.stan', line 72, column 9 to column 14)", + " (in 'laplace_functionals.stan', line 76, column 9 to column 14)", + " (in 'laplace_functionals.stan', line 84, column 15 to column 20)", + " (in 'laplace_functionals.stan', line 84, column 30 to column 35)", + " (in 'laplace_functionals.stan', line 84, column 37 to column 42)", + " (in 'laplace_functionals.stan', line 88, column 15 to column 20)", + " (in 'laplace_functionals.stan', line 88, column 30 to column 35)", + " (in 'laplace_functionals.stan', line 88, column 37 to column 42)", " (in 'laplace_functionals.stan', line 7, column 4 to column 61)", " (in 'laplace_functionals.stan', line 5, column 34 to line 8, column 3)", " (in 'laplace_functionals.stan', line 12, column 11 to column 16)", @@ -8081,7 +8097,7 @@ ll_function(const T0__& theta_arg__, const T1__& eta, const T2__& // suppress unused var warning (void) DUMMY_VAR__; try { - current_statement__ = 36; + current_statement__ = 52; return stan::math::neg_binomial_2_lpmf(y, stan::math::exp(stan::math::add(log_ye, theta)), eta); } catch (const std::exception& e) { @@ -8113,25 +8129,25 @@ K_function(const T0__& x, const T1__& n_obs, const T2__& alpha, const T3__& // suppress unused var warning (void) DUMMY_VAR__; try { - current_statement__ = 38; + current_statement__ = 54; stan::math::validate_non_negative_index("K", "n_obs", n_obs); - current_statement__ = 39; + current_statement__ = 55; stan::math::validate_non_negative_index("K", "n_obs", n_obs); Eigen::Matrix K = Eigen::Matrix::Constant(n_obs, n_obs, DUMMY_VAR__); - current_statement__ = 40; + current_statement__ = 56; stan::model::assign(K, stan::math::gp_exp_quad_cov(x, alpha, rho), "assigning variable K"); - current_statement__ = 42; + current_statement__ = 58; for (int i = 1; i <= n_obs; ++i) { - current_statement__ = 41; + current_statement__ = 57; stan::model::assign(K, (stan::model::rvalue(K, "K", stan::model::index_uni(i), stan::model::index_uni(i)) + 1e-8), "assigning variable K", stan::model::index_uni(i), stan::model::index_uni(i)); } - current_statement__ = 43; + current_statement__ = 59; return K; } catch (const std::exception& e) { stan::lang::rethrow_located(e, locations_array__[current_statement__]); @@ -8181,29 +8197,29 @@ class laplace_functionals_model final : public model_base_crtp::min(); pos__ = 1; - current_statement__ = 11; + current_statement__ = 21; context__.validate_dims("data initialization", "n_obs", "int", std::vector{}); n_obs = std::numeric_limits::min(); - current_statement__ = 11; + current_statement__ = 21; n_obs = context__.vals_i("n_obs")[(1 - 1)]; - current_statement__ = 12; + current_statement__ = 22; context__.validate_dims("data initialization", "n_coordinates", "int", std::vector{}); n_coordinates = std::numeric_limits::min(); - current_statement__ = 12; + current_statement__ = 22; n_coordinates = context__.vals_i("n_coordinates")[(1 - 1)]; - current_statement__ = 13; + current_statement__ = 23; stan::math::validate_non_negative_index("y", "n_obs", n_obs); - current_statement__ = 14; + current_statement__ = 24; context__.validate_dims("data initialization", "y", "int", std::vector{static_cast(n_obs)}); y = std::vector(n_obs, std::numeric_limits::min()); - current_statement__ = 14; + current_statement__ = 24; y = context__.vals_i("y"); - current_statement__ = 15; + current_statement__ = 25; stan::math::validate_non_negative_index("ye", "n_obs", n_obs); - current_statement__ = 16; + current_statement__ = 26; context__.validate_dims("data initialization", "ye", "double", std::vector{static_cast(n_obs)}); ye_data__ = Eigen::Matrix::Constant(n_obs, @@ -8212,7 +8228,7 @@ class laplace_functionals_model final : public model_base_crtp ye_flat__; - current_statement__ = 16; + current_statement__ = 26; ye_flat__ = context__.vals_r("ye"); pos__ = 1; for (int sym1__ = 1; sym1__ <= n_obs; ++sym1__) { @@ -8221,12 +8237,12 @@ class laplace_functionals_model final : public model_base_crtp{static_cast(n_obs), static_cast(n_coordinates)}); @@ -8235,7 +8251,7 @@ class laplace_functionals_model final : public model_base_crtp::quiet_NaN())); { std::vector x_flat__; - current_statement__ = 19; + current_statement__ = 29; x_flat__ = context__.vals_r("x"); pos__ = 1; for (int sym1__ = 1; sym1__ <= n_coordinates; ++sym1__) { @@ -8247,79 +8263,94 @@ class laplace_functionals_model final : public model_base_crtp{}); rho_location_prior = std::numeric_limits::quiet_NaN(); - current_statement__ = 20; + current_statement__ = 30; rho_location_prior = context__.vals_r("rho_location_prior")[(1 - 1)]; - current_statement__ = 21; + current_statement__ = 31; context__.validate_dims("data initialization", "rho_scale_prior", "double", std::vector{}); rho_scale_prior = std::numeric_limits::quiet_NaN(); - current_statement__ = 21; + current_statement__ = 31; rho_scale_prior = context__.vals_r("rho_scale_prior")[(1 - 1)]; - current_statement__ = 22; + current_statement__ = 32; context__.validate_dims("data initialization", "alpha_location_prior", "double", std::vector{}); alpha_location_prior = std::numeric_limits::quiet_NaN(); - current_statement__ = 22; + current_statement__ = 32; alpha_location_prior = context__.vals_r("alpha_location_prior")[(1 - 1)]; - current_statement__ = 23; + current_statement__ = 33; context__.validate_dims("data initialization", "alpha_scale_prior", "double", std::vector{}); alpha_scale_prior = std::numeric_limits::quiet_NaN(); - current_statement__ = 23; + current_statement__ = 33; alpha_scale_prior = context__.vals_r("alpha_scale_prior")[(1 - 1)]; - current_statement__ = 24; + current_statement__ = 34; stan::math::validate_non_negative_index("log_ye", "n_obs", n_obs); - current_statement__ = 25; + current_statement__ = 35; log_ye_data__ = Eigen::Matrix::Constant(n_obs, std::numeric_limits::quiet_NaN()); new (&log_ye) Eigen::Map>(log_ye_data__.data(), n_obs); - current_statement__ = 25; + current_statement__ = 35; stan::model::assign(log_ye, stan::math::log(ye), "assigning variable log_ye"); - current_statement__ = 26; + current_statement__ = 36; stan::math::validate_non_negative_index("theta_0", "n_obs", n_obs); - current_statement__ = 27; + current_statement__ = 37; theta_0_data__ = Eigen::Matrix::Constant(n_obs, std::numeric_limits::quiet_NaN()); new (&theta_0) Eigen::Map>(theta_0_data__.data(), n_obs); - current_statement__ = 27; + current_statement__ = 37; stan::model::assign(theta_0, stan::math::rep_vector(0.0, n_obs), "assigning variable theta_0"); - current_statement__ = 28; + current_statement__ = 38; tolerance = std::numeric_limits::quiet_NaN(); - current_statement__ = 28; + current_statement__ = 38; tolerance = 1e-6; - current_statement__ = 29; + current_statement__ = 39; max_num_steps = std::numeric_limits::min(); - current_statement__ = 29; + current_statement__ = 39; max_num_steps = 100; - current_statement__ = 30; + current_statement__ = 40; hessian_block_size = std::numeric_limits::min(); - current_statement__ = 30; + current_statement__ = 40; hessian_block_size = 1; - current_statement__ = 31; + current_statement__ = 41; solver = std::numeric_limits::min(); - current_statement__ = 31; + current_statement__ = 41; solver = 1; - current_statement__ = 32; + current_statement__ = 42; max_steps_line_search = std::numeric_limits::min(); - current_statement__ = 32; + current_statement__ = 42; max_steps_line_search = 0; - current_statement__ = 33; + current_statement__ = 43; allow_fallthrough = std::numeric_limits::min(); - current_statement__ = 33; + current_statement__ = 43; allow_fallthrough = 1; - current_statement__ = 34; + current_statement__ = 44; stan::math::validate_non_negative_index("theta", "n_obs", n_obs); - current_statement__ = 35; + current_statement__ = 45; stan::math::validate_non_negative_index("theta2", "n_obs", n_obs); + current_statement__ = 46; + stan::math::validate_non_negative_index("mean_chol.1", "n_obs", n_obs); + current_statement__ = 47; + stan::math::validate_non_negative_index("mean_chol.2", "n_obs", n_obs); + current_statement__ = 48; + stan::math::validate_non_negative_index("mean_chol.2", "n_obs", n_obs); + current_statement__ = 49; + stan::math::validate_non_negative_index("mean_chol_tol.1", "n_obs", + n_obs); + current_statement__ = 50; + stan::math::validate_non_negative_index("mean_chol_tol.2", "n_obs", + n_obs); + current_statement__ = 51; + stan::math::validate_non_negative_index("mean_chol_tol.2", "n_obs", + n_obs); } catch (const std::exception& e) { stan::lang::rethrow_located(e, locations_array__[current_statement__]); } @@ -8369,22 +8400,22 @@ class laplace_functionals_model final : public model_base_crtp(0, lp__); { - current_statement__ = 6; + current_statement__ = 8; lp_accum__.add(stan::math::inv_gamma_lpdf(rho, rho_location_prior, rho_scale_prior)); - current_statement__ = 7; + current_statement__ = 9; lp_accum__.add(stan::math::inv_gamma_lpdf(alpha, alpha_location_prior, alpha_scale_prior)); - current_statement__ = 8; + current_statement__ = 10; lp_accum__.add(stan::math::normal_lpdf(eta, static_cast(0), static_cast(1))); - current_statement__ = 9; + current_statement__ = 11; lp_accum__.add(stan::math::laplace_marginal(ll_function_functor__(), std::forward_as_tuple(eta, log_ye, y), hessian_block_size, K_function_functor__(), std::forward_as_tuple(x, n_obs, alpha, rho), pstream__)); - current_statement__ = 10; + current_statement__ = 12; lp_accum__.add(stan::math::laplace_marginal_tol( ll_function_functor__(), std::forward_as_tuple(eta, log_ye, y), @@ -8393,6 +8424,51 @@ class laplace_functionals_model final : public model_base_crtp, + Eigen::Matrix> mean_chol = + std::tuple, + Eigen::Matrix>{Eigen::Matrix::Constant(n_obs, + DUMMY_VAR__), + Eigen::Matrix::Constant(n_obs, n_obs, + DUMMY_VAR__)}; + current_statement__ = 16; + stan::model::assign(mean_chol, + stan::math::laplace_latent_solve(ll_function_functor__(), + std::forward_as_tuple(1.0, log_ye, y), hessian_block_size, + K_function_functor__(), + std::forward_as_tuple(x, n_obs, 1.0, 1.0), pstream__), + "assigning variable mean_chol"); + current_statement__ = 17; + stan::math::validate_non_negative_index("mean_chol_tol", "n_obs", + n_obs); + current_statement__ = 18; + stan::math::validate_non_negative_index("mean_chol_tol", "n_obs", + n_obs); + current_statement__ = 19; + stan::math::validate_non_negative_index("mean_chol_tol", "n_obs", + n_obs); + std::tuple, + Eigen::Matrix> mean_chol_tol = + std::tuple, + Eigen::Matrix>{Eigen::Matrix::Constant(n_obs, + DUMMY_VAR__), + Eigen::Matrix::Constant(n_obs, n_obs, + DUMMY_VAR__)}; + current_statement__ = 20; + stan::model::assign(mean_chol_tol, + stan::math::laplace_latent_solve_tol(ll_function_functor__(), + std::forward_as_tuple(1.0, log_ye, y), hessian_block_size, + K_function_functor__(), + std::forward_as_tuple(x, n_obs, 1.0, 1.0), + std::forward_as_tuple(theta_0, tolerance, max_num_steps, solver, + max_steps_line_search, allow_fallthrough), pstream__), + "assigning variable mean_chol_tol"); } } catch (const std::exception& e) { stan::lang::rethrow_located(e, locations_array__[current_statement__]); @@ -8437,22 +8513,22 @@ class laplace_functionals_model final : public model_base_crtp(0, lp__); { - current_statement__ = 6; + current_statement__ = 8; lp_accum__.add(stan::math::inv_gamma_lpdf(rho, rho_location_prior, rho_scale_prior)); - current_statement__ = 7; + current_statement__ = 9; lp_accum__.add(stan::math::inv_gamma_lpdf(alpha, alpha_location_prior, alpha_scale_prior)); - current_statement__ = 8; + current_statement__ = 10; lp_accum__.add(stan::math::normal_lpdf(eta, static_cast(0), static_cast(1))); - current_statement__ = 9; + current_statement__ = 11; lp_accum__.add(stan::math::laplace_marginal(ll_function_functor__(), std::forward_as_tuple(eta, log_ye, y), hessian_block_size, K_function_functor__(), std::forward_as_tuple(x, n_obs, alpha, rho), pstream__)); - current_statement__ = 10; + current_statement__ = 12; lp_accum__.add(stan::math::laplace_marginal_tol( ll_function_functor__(), std::forward_as_tuple(eta, log_ye, y), @@ -8461,6 +8537,51 @@ class laplace_functionals_model final : public model_base_crtp, + Eigen::Matrix> mean_chol = + std::tuple, + Eigen::Matrix>{Eigen::Matrix::Constant(n_obs, + DUMMY_VAR__), + Eigen::Matrix::Constant(n_obs, n_obs, + DUMMY_VAR__)}; + current_statement__ = 16; + stan::model::assign(mean_chol, + stan::math::laplace_latent_solve(ll_function_functor__(), + std::forward_as_tuple(1.0, log_ye, y), hessian_block_size, + K_function_functor__(), + std::forward_as_tuple(x, n_obs, 1.0, 1.0), pstream__), + "assigning variable mean_chol"); + current_statement__ = 17; + stan::math::validate_non_negative_index("mean_chol_tol", "n_obs", + n_obs); + current_statement__ = 18; + stan::math::validate_non_negative_index("mean_chol_tol", "n_obs", + n_obs); + current_statement__ = 19; + stan::math::validate_non_negative_index("mean_chol_tol", "n_obs", + n_obs); + std::tuple, + Eigen::Matrix> mean_chol_tol = + std::tuple, + Eigen::Matrix>{Eigen::Matrix::Constant(n_obs, + DUMMY_VAR__), + Eigen::Matrix::Constant(n_obs, n_obs, + DUMMY_VAR__)}; + current_statement__ = 20; + stan::model::assign(mean_chol_tol, + stan::math::laplace_latent_solve_tol(ll_function_functor__(), + std::forward_as_tuple(1.0, log_ye, y), hessian_block_size, + K_function_functor__(), + std::forward_as_tuple(x, n_obs, 1.0, 1.0), + std::forward_as_tuple(theta_0, tolerance, max_num_steps, solver, + max_steps_line_search, allow_fallthrough), pstream__), + "assigning variable mean_chol_tol"); } } catch (const std::exception& e) { stan::lang::rethrow_located(e, locations_array__[current_statement__]); @@ -8548,8 +8669,42 @@ class laplace_functionals_model final : public model_base_crtp, Eigen::Matrix> + mean_chol = + std::tuple, Eigen::Matrix>{ + Eigen::Matrix::Constant(n_obs, + std::numeric_limits::quiet_NaN()), + Eigen::Matrix::Constant(n_obs, n_obs, + std::numeric_limits::quiet_NaN())}; + current_statement__ = 6; + stan::model::assign(mean_chol, + stan::math::laplace_latent_solve(ll_function_functor__(), + std::forward_as_tuple(eta, log_ye, y), hessian_block_size, + K_function_functor__(), + std::forward_as_tuple(x, n_obs, alpha, rho), pstream__), + "assigning variable mean_chol"); + std::tuple, Eigen::Matrix> + mean_chol_tol = + std::tuple, Eigen::Matrix>{ + Eigen::Matrix::Constant(n_obs, + std::numeric_limits::quiet_NaN()), + Eigen::Matrix::Constant(n_obs, n_obs, + std::numeric_limits::quiet_NaN())}; + current_statement__ = 7; + stan::model::assign(mean_chol_tol, + stan::math::laplace_latent_solve_tol(ll_function_functor__(), + std::forward_as_tuple(eta, log_ye, y), hessian_block_size, + K_function_functor__(), + std::forward_as_tuple(x, n_obs, alpha, rho), + std::forward_as_tuple(theta_0, tolerance, max_num_steps, solver, + max_steps_line_search, allow_fallthrough), pstream__), + "assigning variable mean_chol_tol"); out__.write(theta); out__.write(theta2); + out__.write(std::get<0>(mean_chol)); + out__.write(std::get<1>(mean_chol)); + out__.write(std::get<0>(mean_chol_tol)); + out__.write(std::get<1>(mean_chol_tol)); } catch (const std::exception& e) { stan::lang::rethrow_located(e, locations_array__[current_statement__]); } @@ -8631,7 +8786,9 @@ class laplace_functionals_model final : public model_base_crtp{"alpha", "rho", "eta"}; if (emit_transformed_parameters__) {} if (emit_generated_quantities__) { - std::vector temp{"theta", "theta2"}; + std::vector + temp{"theta", "theta2", "mean_chol.1", "mean_chol.2", + "mean_chol_tol.1", "mean_chol_tol.2"}; names__.reserve(names__.size() + temp.size()); names__.insert(names__.end(), temp.begin(), temp.end()); } @@ -8646,7 +8803,13 @@ class laplace_functionals_model final : public model_base_crtp> temp{std::vector{static_cast(n_obs)}, - std::vector{static_cast(n_obs)}}; + std::vector{static_cast(n_obs)}, + std::vector{static_cast(n_obs)}, + std::vector{static_cast(n_obs), + static_cast(n_obs)}, + std::vector{static_cast(n_obs)}, + std::vector{static_cast(n_obs), + static_cast(n_obs)}}; dimss__.reserve(dimss__.size() + temp.size()); dimss__.insert(dimss__.end(), temp.begin(), temp.end()); } @@ -8668,6 +8831,28 @@ class laplace_functionals_model final : public model_base_crtp inline void @@ -8705,7 +8912,7 @@ class laplace_functionals_model final : public model_base_crtp params_i; @@ -8723,7 +8930,7 @@ class laplace_functionals_model final : public model_base_crtp(num_to_write, diff --git a/test/integration/good/code-gen/laplace_functionals.stan b/test/integration/good/code-gen/laplace_functionals.stan index 8948773b2..b9d0a2ef0 100644 --- a/test/integration/good/code-gen/laplace_functionals.stan +++ b/test/integration/good/code-gen/laplace_functionals.stan @@ -57,6 +57,16 @@ model { (theta_0, tolerance, max_num_steps, solver, max_steps_line_search, allow_fallthrough)); + tuple(vector[n_obs], matrix[n_obs, n_obs]) mean_chol + = laplace_latent_solve(ll_function, (1.0, log_ye, y), hessian_block_size, + K_function, (x, n_obs, 1.0, 1.0)); + + tuple(vector[n_obs], matrix[n_obs, n_obs]) mean_chol_tol + = laplace_latent_solve_tol(ll_function, (1.0, log_ye, y), + hessian_block_size, K_function, + (x, n_obs, 1.0, 1.0), + (theta_0, tolerance, max_num_steps, solver, + max_steps_line_search, allow_fallthrough)); } generated quantities { vector[n_obs] theta = laplace_latent_rng(ll_function, (eta, log_ye, y), @@ -71,4 +81,15 @@ generated quantities { (theta_0, tolerance, max_num_steps, solver, max_steps_line_search, allow_fallthrough)); + tuple(vector[n_obs], matrix[n_obs, n_obs]) mean_chol + = laplace_latent_solve(ll_function, (eta, log_ye, y), hessian_block_size, + K_function, (x, n_obs, alpha, rho)); + + tuple(vector[n_obs], matrix[n_obs, n_obs]) mean_chol_tol + = laplace_latent_solve_tol(ll_function, (eta, log_ye, y), + hessian_block_size, K_function, + (x, n_obs, alpha, rho), + (theta_0, tolerance, max_num_steps, solver, + max_steps_line_search, allow_fallthrough)); + }