#ifndef __FILE_GSMUSR_H_SEEN__
#define __FILE_GSMUSR_H_SEEN__
/* ----------------------------------------------------------------------------

Copyright (C) 2008, 2009.

A. Ronald Gallant
Post Office Box 659
Chapel Hill NC 27514-0659
USA

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

-----------------------------------------------------------------------------*/

//#define DEBUG_GMUSR
#undef DEBUG_GMUSR

/*
Parameter  Name     Meaning                                        Plausible

theta[1]   delta    Discount factor                                0.9992  
theta[2]   gamma    Coefficient of risk aversion                   10.0   
theta[3]   psi      Elasticity of intertemporal substitution       1.5
theta[4]   mu_c;    Location parameter of log consumption growth   0.0015
theta[5]   rho      Autoregressive parameter of lrr                0.983   
theta[6]   phi_e    Scale parameter of lrr                         0.032    
theta[7]   varbar   Location parameter of squared volatility       0.0064^2
theta[8]   nu       Autoregressive parameter of squared volatility 0.988
theta[9]   sig_w    Scale parameter of squared volatility          0.000004
theta[10]  mu_d     Location parameter of log dividend growth      0.0015
theta[11]  phi_d    Leverage parameter on lrr                      3.0
theta[12]  pi_d     Correlation param on consumption innovation    1.8  
theta[13]  phi_u    Scale parameter of log dividend growth         4.1243

stats[1]   br       Bond returns                                   1.000743618
stats[2]   bv       Variance of bond returns                       0.000024083
stats[3]   sr       Stock returns                                  1.002851
stats[4]   sv       Variance of stock returns                      0.001771989

Parameter  Name     Reasonable support

theta[1]   delta    [ 0.9, 0.99999]
theta[2]   gamma    [ 0.25, 100.0]
theta[3]   psi      [ 1.0001, 5.0]
theta[4]   mu_c     [-0.02, 0.02]
theta[5]   rho      [ 0.0, 1.0]
theta[6]   phi_e    [ 0.0, 1.0]
theta[7]   varbar   [ 0.0, 1.0]
theta[8]   nu       [ 0.0, 0.9995]           
theta[9]   sig_w    [ 0.0, 1.0]
theta[10]  mu_d     [-0.02, 0.02]
theta[11]  phi_d    [ 0.0, 100.0]
theta[12]  pi_d     [ 0.0, 100.0]
theta[13]  phi_u    [ 0.0, 100.0]
*/

#include "libgsm.h"
#include "libsnp.h"
#include "snp.h"

namespace gsm {
    
  class lrr_sci_mod;
  class stat_mod;
  class snp_stat_mod;

  typedef lrr_sci_mod sci_mod_type;
  typedef snp_stat_mod stat_mod_type;

  const INTEGER n_state = 2;       //Number of state variables
  const INTEGER n_sci_parms = 13;  //Number of sci mod parameters
  const INTEGER n_sci_funcs = 4;   //Number of sci mod functionals
  const INTEGER n_stat_funcs = 9;  //Number of stat mod functionals


  struct lrr_sci_mod_variables {
    INTEGER n0;  // for lags and to allow transients to dissipate
    INTEGER n;   // simulation length
    INTEGER n1;  // for leads
    INTEGER nt;  // nt = n0 + n + n1
    scl::realmat log_consumption_growth;
    scl::realmat consumption_growth;
    scl::realmat consumption;
    scl::realmat long_run_risk;
    scl::realmat squared_volatility;
    scl::realmat volatility;
    scl::realmat log_dividend_growth;
    scl::realmat dividend_growth;
    scl::realmat dividend;
    scl::realmat zeta;
    scl::realmat Y;
    scl::realmat log_mrs;
    scl::realmat mrs;
    scl::realmat log_pc_ratio;
    scl::realmat geometric_consumption_return;
    scl::realmat geometric_risk_free_rate;
    scl::realmat log_pd_ratio;
    scl::realmat geometric_stock_return;
    lrr_sci_mod_variables() { }
    lrr_sci_mod_variables(INTEGER n_lag, INTEGER n_sim, INTEGER n_lead)
    : n0(n_lag), n(n_sim), n1(n_lead), nt(n0+n+n1),
      log_consumption_growth(nt,1,0.0),
      consumption_growth(nt,1,0.0),
      consumption(nt,1,0.0),
      long_run_risk(nt,1,0.0),
      squared_volatility(nt,1,0.0),
      volatility(nt,1,0.0),
      log_dividend_growth(nt,1,0.0),
      dividend_growth(nt,1,0.0),
      dividend(nt,1,0.0),
      zeta(nt,3,0.0),
      Y(nt,3,0.0),
      log_mrs(nt,1,0.0),
      mrs(nt,1,0.0),
      log_pc_ratio(nt,1,0.0),
      geometric_consumption_return(nt,1,0.0),
      geometric_risk_free_rate(nt,1,0.0),
      log_pd_ratio(nt,1,0.0),
      geometric_stock_return(nt,1,0.0)
    { }
    std::vector<std::string> get_lrr_sci_mod_variables(scl::realmat& mv);
  };    

  struct lrr_sci_mod_parameters {
    REAL delta;         // discount factor
    REAL gamma;         // coefficient of risk aversion
    REAL psi;           // elasticity of intertemporal substitution
    REAL mu_c;          // location parameter of log consumption growth 
    REAL rho;           // autoregressive parameter of lrr
    REAL phi_e;         // scale parameter of lrr
    REAL varbar;        // location parameter of squared volatility
    REAL nu;            // autoregressive parameter of squared volatility 
    REAL sig_w;         // scale parameter of squared volatility
    REAL mu_d;          // location parameter of log dividend growth
    REAL phi_d;         // leverage parameter on lrr
    REAL pi_d;          // correlation parameter on consumption innovation
    REAL phi_u;         // scale parameter of log dividend growth
    REAL rpsi;          // convenience parameter
    REAL theta;         // convenience parameter
    lrr_sci_mod_parameters()
    /*
    : delta(0.9992),        // Values supplied by Kiku 
      gamma(10.0), 
      psi(1.5), 
      mu_c(0.0015), 
      rho(0.983), 
      phi_e(0.032), 
      varbar(pow(0.0064,2)), 
      nu(0.988), 
      sig_w(0.0000040), 
      mu_d(0.0015),
      phi_d(3.0),
      pi_d(1.8),
      phi_u(4.1243)
    */
    : delta(0.9992),          // Kiku job market paper
      gamma(10.0), 
      psi(1.5), 
      mu_c(0.0015), 
      rho(0.983), 
      phi_e(0.032), 
      varbar(pow(0.0064,2)), 
      nu(0.988), 
      sig_w(0.0000017), 
      mu_d(0.0012),
      phi_d(2.8),
      pi_d(4.125),
      phi_u(6.2637)
    {
      if (psi <= 0.0) scl::error("Error, lrr_sci_mod_parameters, psi <= 0");
      rpsi = 1.0/psi;
      theta = (1.0 - gamma)/(1.0 - rpsi);
    }
    void set_theta(const scl::realmat& parm)
    {
      if (parm.nrow() != n_sci_parms || parm.ncol() != 1)
        scl::error("Error, lrr_sci_mod, set_theta, bad dimension");
      if (psi <= 0.0) 
        scl::error("Error, lrr_sci_mod_parameters, psi <= 0");
      delta  = parm[1]; 
      gamma  = parm[2]; 
      psi    = parm[3];
      mu_c   = parm[4];
      rho    = parm[5];
      phi_e  = parm[6];
      varbar = parm[7];
      nu     = parm[8];
      sig_w  = parm[9]; 
      mu_d   = parm[10];
      phi_d  = parm[11];
      pi_d   = parm[12];
      phi_u  = parm[13];
      rpsi  = 1.0/psi;
      theta = (1.0 - gamma)/(1.0 - rpsi);
    }
    void get_theta(scl::realmat& parm)
    {
      parm.resize(n_sci_parms,1);
      parm[1] = delta;
      parm[2] = gamma;
      parm[3] = psi;
      parm[4] = mu_c;
      parm[5] = rho;
      parm[6] = phi_e;
      parm[7] = varbar;
      parm[8] = nu;
      parm[9] = sig_w;
      parm[10] = mu_d;
      parm[11] = phi_d;
      parm[12] = pi_d;
      parm[13] = phi_u;
    }
  };

  extern std::ostream& 
  operator<<(std::ostream& os, const lrr_sci_mod_parameters& mp);

  class lrr_sci_mod : public libgsm::sci_mod_base {
  private:
    lrr_sci_mod_parameters mp;
    lrr_sci_mod_variables mv;
    bool gen_sim_cgsr(scl::realmat& sim);
    bool gen_sim_cgsr(scl::realmat& sim, scl::realmat& func);
    std::ostream& debug;
    bool debug_switch;
    INTEGER n_dat_vars;    //Number of simulated variables
  public:
    lrr_sci_mod
      (const scl::realmat* dat_ptr, const std::vector<std::string>& pfvec,
       const std::vector<std::string>& alvec, std::ostream& detail);
    INTEGER len_parm() { return n_sci_parms; }
    INTEGER len_func() { return n_sci_funcs; }
    void get_parm(scl::realmat& parm) { mp.get_theta(parm); }
    void set_parm(const scl::realmat& parm) { mp.set_theta(parm); }
    bool support(const scl::realmat& parm);
    bool gen_sim(scl::realmat& sim, scl::realmat& func);
    scl::den_val prior(const scl::realmat& parm, const scl::realmat& func);
    scl::realmat annualize_parms(const scl::realmat& theta);
    scl::realmat annualize_funcs(const scl::realmat& stats);
  };
  
  class stat_mod : public libgsm::stat_mod_base {
  private:
    scl::realmat  b, B; // location function parameters
    scl::realmat  p, P; // variance function parameters, the ARCH or MA part
    scl::realmat  G;    // variance function parameters, the GARCH or AR part
    const scl::realmat* Y;    // the data, which is Y(d,n)
    INTEGER d;  // dimension d of the model, inferred from row dimension of Y
    INTEGER n;  // sample size n, inferred from column dimension of Y
    INTEGER lagu; // lags in mean function
    INTEGER lagR; // lags in MA-part of variance function
    INTEGER lagG; // lags in AR-part of variance function
    INTEGER lR; // dimension of vech(R), R is Cholesky factor of variance
    INTEGER len_sim;
    REAL get_eta(INTEGER i);
    void set_eta(INTEGER i, REAL v);
  public:
    stat_mod
      (const scl::realmat* dat_ptr, const std::vector<std::string>& pfvec,
       const std::vector<std::string>& alvec, std::ostream& detail);
    INTEGER len_parm() { return d + d*d*lagu + lR + lR*d*lagR + lagG; } 
    INTEGER len_func() { return n_stat_funcs; }
    void get_parm(scl::realmat& parm);
    void set_parm(const scl::realmat& parm);
    void set_data_ptr(const scl::realmat* dat_ptr);
    bool gen_sim(scl::realmat& sim, scl::realmat& func);
    bool support(const scl::realmat& parm);
    scl::den_val prior(const scl::realmat& parm, const scl::realmat& func);
    scl::den_val logl();
  };

  class snp_stat_mod : public libgsm::stat_mod_base {
  private:
    scl::realmat Xlags;      // First few transformed and squashed
    scl::realmat Ylags;      // observations to get lags for gen_sim
    scl::realmat X;          // Transformed and squashed data or simulation
    scl::realmat Y;          // maintained by set_data_ptr for use by logl, 
    snp::trnfrm tr;
    snp::snpll ll;
    INTEGER lsim;
    INTEGER spin;
    INTEGER lrho;
    INTEGER lstats;
    bool snp_simulate(INT_32BIT& iseed, scl::realmat& sim);
  public:
    snp_stat_mod
      (const scl::realmat* dat_ptr, const std::vector<std::string>& pfvec,
       const std::vector<std::string>& alvec, std::ostream& detail);
    INTEGER len_parm() {return lrho;}
    INTEGER len_func() {return lstats;}
    INTEGER num_obs() {return Y.get_cols();}
    void    get_parm(scl::realmat& rho);
    void    set_parm(const scl::realmat& rho);
    void    set_data_ptr(const scl::realmat* dat_ptr);
    bool    support(const scl::realmat& rho);
    scl::den_val prior(const scl::realmat& rho, const scl::realmat& stats);
    bool    gen_sim(scl::realmat& sim, scl::realmat& stats);
    scl::den_val logl();
    scl::den_val logl(scl::realmat& dlogl);
    REAL    penalty(scl::realmat& dpenalty);
  };
}

#endif
