#ifndef __FILE_EMMUSR_H_SEEN__
#define __FILE_EMMUSR_H_SEEN__
/* ----------------------------------------------------------------------------

Copyright (C) 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_EMMUSR
#undef DEBUG_EMMUSR

/*
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
theta[14]  mudc     Mean of log dividend/consumption series       -3.3857 

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]
theta[14]  mudc     [-10.0, 10.0]
*/

#include "libsnp.h"
#include "libsmm.h"
#include "emm_base.h"
#include "snp.h"

namespace emm {
    
  class lrr_usrmod;
  typedef lrr_usrmod usrmod_type;

  const INTEGER n_state = 2;   //Number of state variables
  const INTEGER n_parms = 14;  //Number of parameters
  const INTEGER n_funcs = 4;   //Number of functionals
  const INTEGER n_datum = 4;   //Number of simulated variables


  struct lrr_usrmod_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 price_dividend_ratio;
    scl::realmat geometric_stock_return;
    lrr_usrmod_variables() { }
    lrr_usrmod_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),
      price_dividend_ratio(nt,1,0.0),
      geometric_stock_return(nt,1,0.0)
    { }
    std::vector<std::string> get_lrr_usrmod_variables(scl::realmat& mv);
  };    

  struct lrr_usrmod_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 mudc;          // mean of log dividend/consumption series
    REAL rpsi;          // convenience parameter
    REAL theta;         // convenience parameter
    lrr_usrmod_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),
      mudc(-3.3857)
    {
      if (psi <= 0.0) scl::error("Error, lrr_usrmod_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_parms || parm.ncol() != 1)
        scl::error("Error, lrr_usrmod, set_theta, bad dimension");
      if (psi <= 0.0) 
        scl::error("Error, lrr_usrmod_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];
      mudc   = parm[14];
      rpsi  = 1.0/psi;
      theta = (1.0 - gamma)/(1.0 - rpsi);
    }
    void get_theta(scl::realmat& parm)
    {
      parm.resize(n_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;
      parm[14] = mudc;
    }
  };

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

  class lrr_usrmod : public libsmm::usrmod_base {
  private:
    lrr_usrmod_parameters mp;
    lrr_usrmod_variables mv;
    scl::realmat data;
    std::ostream* debug;
    bool debug_switch;
    INT_32BIT bootstrap_seed;
    INT_32BIT simulation_seed;
    bool make_sim(INT_32BIT& seed, scl::realmat& sim);
  public:
    lrr_usrmod(const scl::realmat& dat, INTEGER len_mod_parm,
      INTEGER len_mod_func, const std::vector<std::string>& mod_pfvec,
      const std::vector<std::string>& mod_alvec, std::ostream& detail);
    INTEGER len_rho() { return n_parms; }
    INTEGER len_stats() { return n_funcs; }
    void get_rho(scl::realmat& parm) { mp.get_theta(parm); }
    void set_rho(const scl::realmat& parm) { mp.set_theta(parm); }
    bool support(const scl::realmat& parm);
    bool gen_sim(scl::realmat& sim);
    bool gen_sim(scl::realmat& sim, scl::realmat& func);
    bool gen_bootstrap(std::vector<scl::realmat>& bs);
    scl::den_val prior(const scl::realmat& parm, const scl::realmat& func);
    void write_usrvar(const char* filename);
  };
  
}

#endif
