// Code generated by Stan version 2.19.1

#include <stan/model/model_header.hpp>

namespace model98f413f5fb_bay_port_namespace {

using std::istream;
using std::string;
using std::stringstream;
using std::vector;
using stan::io::dump;
using stan::math::lgamma;
using stan::model::prob_grad;
using namespace stan::math;

static int current_statement_begin__;

stan::io::program_reader prog_reader__() {
    stan::io::program_reader reader;
    reader.add_event(0, 0, "start", "model98f413f5fb_bay_port");
    reader.add_event(34, 32, "end", "model98f413f5fb_bay_port");
    return reader;
}

class model98f413f5fb_bay_port : public prob_grad {
private:
        int T;
        int N;
        double nu;
        double tau;
        vector_d eta;
        matrix_d R;
        matrix_d omega;
public:
    model98f413f5fb_bay_port(stan::io::var_context& context__,
        std::ostream* pstream__ = 0)
        : prob_grad(0) {
        ctor_body(context__, 0, pstream__);
    }

    model98f413f5fb_bay_port(stan::io::var_context& context__,
        unsigned int random_seed__,
        std::ostream* pstream__ = 0)
        : prob_grad(0) {
        ctor_body(context__, random_seed__, pstream__);
    }

    void ctor_body(stan::io::var_context& context__,
                   unsigned int random_seed__,
                   std::ostream* pstream__) {
        typedef double local_scalar_t__;

        boost::ecuyer1988 base_rng__ =
          stan::services::util::create_rng(random_seed__, 0);
        (void) base_rng__;  // suppress unused var warning

        current_statement_begin__ = -1;

        static const char* function__ = "model98f413f5fb_bay_port_namespace::model98f413f5fb_bay_port";
        (void) function__;  // dummy to suppress unused var warning
        size_t pos__;
        (void) pos__;  // dummy to suppress unused var warning
        std::vector<int> vals_i__;
        std::vector<double> vals_r__;
        local_scalar_t__ DUMMY_VAR__(std::numeric_limits<double>::quiet_NaN());
        (void) DUMMY_VAR__;  // suppress unused var warning

        try {
            // initialize data block variables from context__
            current_statement_begin__ = 5;
            context__.validate_dims("data initialization", "T", "int", context__.to_vec());
            T = int(0);
            vals_i__ = context__.vals_i("T");
            pos__ = 0;
            T = vals_i__[pos__++];
            check_greater_or_equal(function__, "T", T, 5);

            current_statement_begin__ = 6;
            context__.validate_dims("data initialization", "N", "int", context__.to_vec());
            N = int(0);
            vals_i__ = context__.vals_i("N");
            pos__ = 0;
            N = vals_i__[pos__++];
            check_greater_or_equal(function__, "N", N, 2);

            current_statement_begin__ = 7;
            context__.validate_dims("data initialization", "nu", "double", context__.to_vec());
            nu = double(0);
            vals_r__ = context__.vals_r("nu");
            pos__ = 0;
            nu = vals_r__[pos__++];
            check_greater_or_equal(function__, "nu", nu, (N - 1));

            current_statement_begin__ = 8;
            context__.validate_dims("data initialization", "tau", "double", context__.to_vec());
            tau = double(0);
            vals_r__ = context__.vals_r("tau");
            pos__ = 0;
            tau = vals_r__[pos__++];
            check_greater_or_equal(function__, "tau", tau, 0);

            current_statement_begin__ = 9;
            validate_non_negative_index("eta", "N", N);
            context__.validate_dims("data initialization", "eta", "vector_d", context__.to_vec(N));
            eta = Eigen::Matrix<double, Eigen::Dynamic, 1>(N);
            vals_r__ = context__.vals_r("eta");
            pos__ = 0;
            size_t eta_j_1_max__ = N;
            for (size_t j_1__ = 0; j_1__ < eta_j_1_max__; ++j_1__) {
                eta(j_1__) = vals_r__[pos__++];
            }

            current_statement_begin__ = 10;
            validate_non_negative_index("R", "T", T);
            validate_non_negative_index("R", "N", N);
            context__.validate_dims("data initialization", "R", "matrix_d", context__.to_vec(T,N));
            R = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>(T, N);
            vals_r__ = context__.vals_r("R");
            pos__ = 0;
            size_t R_j_2_max__ = N;
            size_t R_j_1_max__ = T;
            for (size_t j_2__ = 0; j_2__ < R_j_2_max__; ++j_2__) {
                for (size_t j_1__ = 0; j_1__ < R_j_1_max__; ++j_1__) {
                    R(j_1__, j_2__) = vals_r__[pos__++];
                }
            }

            current_statement_begin__ = 11;
            validate_non_negative_index("omega", "N", N);
            validate_non_negative_index("omega", "N", N);
            context__.validate_dims("data initialization", "omega", "matrix_d", context__.to_vec(N,N));
            omega = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>(N, N);
            vals_r__ = context__.vals_r("omega");
            pos__ = 0;
            size_t omega_j_2_max__ = N;
            size_t omega_j_1_max__ = N;
            for (size_t j_2__ = 0; j_2__ < omega_j_2_max__; ++j_2__) {
                for (size_t j_1__ = 0; j_1__ < omega_j_1_max__; ++j_1__) {
                    omega(j_1__, j_2__) = vals_r__[pos__++];
                }
            }
            stan::math::check_cov_matrix(function__, "omega", omega);


            // initialize transformed data variables
            // execute transformed data statements

            // validate transformed data

            // validate, set parameter ranges
            num_params_r__ = 0U;
            param_ranges_i__.clear();
            current_statement_begin__ = 15;
            validate_non_negative_index("mu", "N", N);
            num_params_r__ += N;
            current_statement_begin__ = 16;
            validate_non_negative_index("sigma", "N", N);
            validate_non_negative_index("sigma", "N", N);
            num_params_r__ += (N + ((N * (N - 1)) / 2));
        } catch (const std::exception& e) {
            stan::lang::rethrow_located(e, current_statement_begin__, prog_reader__());
            // Next line prevents compiler griping about no return
            throw std::runtime_error("*** IF YOU SEE THIS, PLEASE REPORT A BUG ***");
        }
    }

    ~model98f413f5fb_bay_port() { }


    void transform_inits(const stan::io::var_context& context__,
                         std::vector<int>& params_i__,
                         std::vector<double>& params_r__,
                         std::ostream* pstream__) const {
        typedef double local_scalar_t__;
        stan::io::writer<double> writer__(params_r__, params_i__);
        size_t pos__;
        (void) pos__; // dummy call to supress warning
        std::vector<double> vals_r__;
        std::vector<int> vals_i__;

        current_statement_begin__ = 15;
        if (!(context__.contains_r("mu")))
            stan::lang::rethrow_located(std::runtime_error(std::string("Variable mu missing")), current_statement_begin__, prog_reader__());
        vals_r__ = context__.vals_r("mu");
        pos__ = 0U;
        validate_non_negative_index("mu", "N", N);
        context__.validate_dims("parameter initialization", "mu", "vector_d", context__.to_vec(N));
        Eigen::Matrix<double, Eigen::Dynamic, 1> mu(N);
        size_t mu_j_1_max__ = N;
        for (size_t j_1__ = 0; j_1__ < mu_j_1_max__; ++j_1__) {
            mu(j_1__) = vals_r__[pos__++];
        }
        try {
            writer__.vector_unconstrain(mu);
        } catch (const std::exception& e) {
            stan::lang::rethrow_located(std::runtime_error(std::string("Error transforming variable mu: ") + e.what()), current_statement_begin__, prog_reader__());
        }

        current_statement_begin__ = 16;
        if (!(context__.contains_r("sigma")))
            stan::lang::rethrow_located(std::runtime_error(std::string("Variable sigma missing")), current_statement_begin__, prog_reader__());
        vals_r__ = context__.vals_r("sigma");
        pos__ = 0U;
        validate_non_negative_index("sigma", "N", N);
        validate_non_negative_index("sigma", "N", N);
        context__.validate_dims("parameter initialization", "sigma", "matrix_d", context__.to_vec(N,N));
        Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> sigma(N, N);
        size_t sigma_j_2_max__ = N;
        size_t sigma_j_1_max__ = N;
        for (size_t j_2__ = 0; j_2__ < sigma_j_2_max__; ++j_2__) {
            for (size_t j_1__ = 0; j_1__ < sigma_j_1_max__; ++j_1__) {
                sigma(j_1__, j_2__) = vals_r__[pos__++];
            }
        }
        try {
            writer__.cov_matrix_unconstrain(sigma);
        } catch (const std::exception& e) {
            stan::lang::rethrow_located(std::runtime_error(std::string("Error transforming variable sigma: ") + e.what()), current_statement_begin__, prog_reader__());
        }

        params_r__ = writer__.data_r();
        params_i__ = writer__.data_i();
    }

    void transform_inits(const stan::io::var_context& context,
                         Eigen::Matrix<double, Eigen::Dynamic, 1>& params_r,
                         std::ostream* pstream__) const {
      std::vector<double> params_r_vec;
      std::vector<int> params_i_vec;
      transform_inits(context, params_i_vec, params_r_vec, pstream__);
      params_r.resize(params_r_vec.size());
      for (int i = 0; i < params_r.size(); ++i)
        params_r(i) = params_r_vec[i];
    }


    template <bool propto__, bool jacobian__, typename T__>
    T__ log_prob(std::vector<T__>& params_r__,
                 std::vector<int>& params_i__,
                 std::ostream* pstream__ = 0) const {

        typedef T__ local_scalar_t__;

        local_scalar_t__ DUMMY_VAR__(std::numeric_limits<double>::quiet_NaN());
        (void) DUMMY_VAR__;  // dummy to suppress unused var warning

        T__ lp__(0.0);
        stan::math::accumulator<T__> lp_accum__;
        try {
            stan::io::reader<local_scalar_t__> in__(params_r__, params_i__);

            // model parameters
            current_statement_begin__ = 15;
            Eigen::Matrix<local_scalar_t__, Eigen::Dynamic, 1> mu;
            (void) mu;  // dummy to suppress unused var warning
            if (jacobian__)
                mu = in__.vector_constrain(N, lp__);
            else
                mu = in__.vector_constrain(N);

            current_statement_begin__ = 16;
            Eigen::Matrix<local_scalar_t__, Eigen::Dynamic, Eigen::Dynamic> sigma;
            (void) sigma;  // dummy to suppress unused var warning
            if (jacobian__)
                sigma = in__.cov_matrix_constrain(N, lp__);
            else
                sigma = in__.cov_matrix_constrain(N);

            // transformed parameters
            current_statement_begin__ = 20;
            validate_non_negative_index("sigma_scaled", "N", N);
            validate_non_negative_index("sigma_scaled", "N", N);
            Eigen::Matrix<local_scalar_t__, Eigen::Dynamic, Eigen::Dynamic> sigma_scaled(N, N);
            stan::math::initialize(sigma_scaled, DUMMY_VAR__);
            stan::math::fill(sigma_scaled, DUMMY_VAR__);

            // transformed parameters block statements
            current_statement_begin__ = 21;
            stan::math::assign(sigma_scaled, multiply((1 / tau), sigma));

            // validate transformed parameters
            const char* function__ = "validate transformed params";
            (void) function__;  // dummy to suppress unused var warning

            current_statement_begin__ = 20;
            size_t sigma_scaled_j_1_max__ = N;
            size_t sigma_scaled_j_2_max__ = N;
            for (size_t j_1__ = 0; j_1__ < sigma_scaled_j_1_max__; ++j_1__) {
                for (size_t j_2__ = 0; j_2__ < sigma_scaled_j_2_max__; ++j_2__) {
                    if (stan::math::is_uninitialized(sigma_scaled(j_1__, j_2__))) {
                        std::stringstream msg__;
                        msg__ << "Undefined transformed parameter: sigma_scaled" << "(" << j_1__ << ", " << j_2__ << ")";
                        stan::lang::rethrow_located(std::runtime_error(std::string("Error initializing variable sigma_scaled: ") + msg__.str()), current_statement_begin__, prog_reader__());
                    }
                }
            }
            stan::math::check_cov_matrix(function__, "sigma_scaled", sigma_scaled);


            // model body

            current_statement_begin__ = 26;
            lp_accum__.add(inv_wishart_log(sigma, nu, omega));
            current_statement_begin__ = 27;
            lp_accum__.add(multi_normal_log(mu, eta, sigma_scaled));
            current_statement_begin__ = 28;
            for (int t = 1; t <= T; ++t) {

                current_statement_begin__ = 29;
                lp_accum__.add(multi_normal_log(get_base1(R, t, "R", 1), mu, sigma));
            }

        } catch (const std::exception& e) {
            stan::lang::rethrow_located(e, current_statement_begin__, prog_reader__());
            // Next line prevents compiler griping about no return
            throw std::runtime_error("*** IF YOU SEE THIS, PLEASE REPORT A BUG ***");
        }

        lp_accum__.add(lp__);
        return lp_accum__.sum();

    } // log_prob()

    template <bool propto, bool jacobian, typename T_>
    T_ log_prob(Eigen::Matrix<T_,Eigen::Dynamic,1>& params_r,
               std::ostream* pstream = 0) const {
      std::vector<T_> vec_params_r;
      vec_params_r.reserve(params_r.size());
      for (int i = 0; i < params_r.size(); ++i)
        vec_params_r.push_back(params_r(i));
      std::vector<int> vec_params_i;
      return log_prob<propto,jacobian,T_>(vec_params_r, vec_params_i, pstream);
    }


    void get_param_names(std::vector<std::string>& names__) const {
        names__.resize(0);
        names__.push_back("mu");
        names__.push_back("sigma");
        names__.push_back("sigma_scaled");
    }


    void get_dims(std::vector<std::vector<size_t> >& dimss__) const {
        dimss__.resize(0);
        std::vector<size_t> dims__;
        dims__.resize(0);
        dims__.push_back(N);
        dimss__.push_back(dims__);
        dims__.resize(0);
        dims__.push_back(N);
        dims__.push_back(N);
        dimss__.push_back(dims__);
        dims__.resize(0);
        dims__.push_back(N);
        dims__.push_back(N);
        dimss__.push_back(dims__);
    }

    template <typename RNG>
    void write_array(RNG& base_rng__,
                     std::vector<double>& params_r__,
                     std::vector<int>& params_i__,
                     std::vector<double>& vars__,
                     bool include_tparams__ = true,
                     bool include_gqs__ = true,
                     std::ostream* pstream__ = 0) const {
        typedef double local_scalar_t__;

        vars__.resize(0);
        stan::io::reader<local_scalar_t__> in__(params_r__, params_i__);
        static const char* function__ = "model98f413f5fb_bay_port_namespace::write_array";
        (void) function__;  // dummy to suppress unused var warning

        // read-transform, write parameters
        Eigen::Matrix<double, Eigen::Dynamic, 1> mu = in__.vector_constrain(N);
        size_t mu_j_1_max__ = N;
        for (size_t j_1__ = 0; j_1__ < mu_j_1_max__; ++j_1__) {
            vars__.push_back(mu(j_1__));
        }

        Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> sigma = in__.cov_matrix_constrain(N);
        size_t sigma_j_2_max__ = N;
        size_t sigma_j_1_max__ = N;
        for (size_t j_2__ = 0; j_2__ < sigma_j_2_max__; ++j_2__) {
            for (size_t j_1__ = 0; j_1__ < sigma_j_1_max__; ++j_1__) {
                vars__.push_back(sigma(j_1__, j_2__));
            }
        }

        double lp__ = 0.0;
        (void) lp__;  // dummy to suppress unused var warning
        stan::math::accumulator<double> lp_accum__;

        local_scalar_t__ DUMMY_VAR__(std::numeric_limits<double>::quiet_NaN());
        (void) DUMMY_VAR__;  // suppress unused var warning

        if (!include_tparams__ && !include_gqs__) return;

        try {
            // declare and define transformed parameters
            current_statement_begin__ = 20;
            validate_non_negative_index("sigma_scaled", "N", N);
            validate_non_negative_index("sigma_scaled", "N", N);
            Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> sigma_scaled(N, N);
            stan::math::initialize(sigma_scaled, DUMMY_VAR__);
            stan::math::fill(sigma_scaled, DUMMY_VAR__);

            // do transformed parameters statements
            current_statement_begin__ = 21;
            stan::math::assign(sigma_scaled, multiply((1 / tau), sigma));

            if (!include_gqs__ && !include_tparams__) return;
            // validate transformed parameters
            const char* function__ = "validate transformed params";
            (void) function__;  // dummy to suppress unused var warning

            current_statement_begin__ = 20;
            stan::math::check_cov_matrix(function__, "sigma_scaled", sigma_scaled);

            // write transformed parameters
            if (include_tparams__) {
                size_t sigma_scaled_j_2_max__ = N;
                size_t sigma_scaled_j_1_max__ = N;
                for (size_t j_2__ = 0; j_2__ < sigma_scaled_j_2_max__; ++j_2__) {
                    for (size_t j_1__ = 0; j_1__ < sigma_scaled_j_1_max__; ++j_1__) {
                        vars__.push_back(sigma_scaled(j_1__, j_2__));
                    }
                }
            }
            if (!include_gqs__) return;
        } catch (const std::exception& e) {
            stan::lang::rethrow_located(e, current_statement_begin__, prog_reader__());
            // Next line prevents compiler griping about no return
            throw std::runtime_error("*** IF YOU SEE THIS, PLEASE REPORT A BUG ***");
        }
    }

    template <typename RNG>
    void write_array(RNG& base_rng,
                     Eigen::Matrix<double,Eigen::Dynamic,1>& params_r,
                     Eigen::Matrix<double,Eigen::Dynamic,1>& vars,
                     bool include_tparams = true,
                     bool include_gqs = true,
                     std::ostream* pstream = 0) const {
      std::vector<double> params_r_vec(params_r.size());
      for (int i = 0; i < params_r.size(); ++i)
        params_r_vec[i] = params_r(i);
      std::vector<double> vars_vec;
      std::vector<int> params_i_vec;
      write_array(base_rng, params_r_vec, params_i_vec, vars_vec, include_tparams, include_gqs, pstream);
      vars.resize(vars_vec.size());
      for (int i = 0; i < vars.size(); ++i)
        vars(i) = vars_vec[i];
    }

    static std::string model_name() {
        return "model98f413f5fb_bay_port";
    }


    void constrained_param_names(std::vector<std::string>& param_names__,
                                 bool include_tparams__ = true,
                                 bool include_gqs__ = true) const {
        std::stringstream param_name_stream__;
        size_t mu_j_1_max__ = N;
        for (size_t j_1__ = 0; j_1__ < mu_j_1_max__; ++j_1__) {
            param_name_stream__.str(std::string());
            param_name_stream__ << "mu" << '.' << j_1__ + 1;
            param_names__.push_back(param_name_stream__.str());
        }
        size_t sigma_j_2_max__ = N;
        size_t sigma_j_1_max__ = N;
        for (size_t j_2__ = 0; j_2__ < sigma_j_2_max__; ++j_2__) {
            for (size_t j_1__ = 0; j_1__ < sigma_j_1_max__; ++j_1__) {
                param_name_stream__.str(std::string());
                param_name_stream__ << "sigma" << '.' << j_1__ + 1 << '.' << j_2__ + 1;
                param_names__.push_back(param_name_stream__.str());
            }
        }

        if (!include_gqs__ && !include_tparams__) return;

        if (include_tparams__) {
            size_t sigma_scaled_j_2_max__ = N;
            size_t sigma_scaled_j_1_max__ = N;
            for (size_t j_2__ = 0; j_2__ < sigma_scaled_j_2_max__; ++j_2__) {
                for (size_t j_1__ = 0; j_1__ < sigma_scaled_j_1_max__; ++j_1__) {
                    param_name_stream__.str(std::string());
                    param_name_stream__ << "sigma_scaled" << '.' << j_1__ + 1 << '.' << j_2__ + 1;
                    param_names__.push_back(param_name_stream__.str());
                }
            }
        }

        if (!include_gqs__) return;
    }


    void unconstrained_param_names(std::vector<std::string>& param_names__,
                                   bool include_tparams__ = true,
                                   bool include_gqs__ = true) const {
        std::stringstream param_name_stream__;
        size_t mu_j_1_max__ = N;
        for (size_t j_1__ = 0; j_1__ < mu_j_1_max__; ++j_1__) {
            param_name_stream__.str(std::string());
            param_name_stream__ << "mu" << '.' << j_1__ + 1;
            param_names__.push_back(param_name_stream__.str());
        }
        size_t sigma_j_1_max__ = (N + ((N * (N - 1)) / 2));
        for (size_t j_1__ = 0; j_1__ < sigma_j_1_max__; ++j_1__) {
            param_name_stream__.str(std::string());
            param_name_stream__ << "sigma" << '.' << j_1__ + 1;
            param_names__.push_back(param_name_stream__.str());
        }

        if (!include_gqs__ && !include_tparams__) return;

        if (include_tparams__) {
            size_t sigma_scaled_j_1_max__ = (N + ((N * (N - 1)) / 2));
            for (size_t j_1__ = 0; j_1__ < sigma_scaled_j_1_max__; ++j_1__) {
                param_name_stream__.str(std::string());
                param_name_stream__ << "sigma_scaled" << '.' << j_1__ + 1;
                param_names__.push_back(param_name_stream__.str());
            }
        }

        if (!include_gqs__) return;
    }

}; // model

}  // namespace

typedef model98f413f5fb_bay_port_namespace::model98f413f5fb_bay_port stan_model;