#ifndef __FILE_LIBGSM_BASE_H_SEEN__
#define __FILE_LIBGSM_BASE_H_SEEN__ 

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

Copyright (C) 2005, 2006, 2008, 2011.

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.

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

#include "libscl.h" 

namespace libgsm {

extern  bool operator==(const scl::den_val& lhs, const scl::den_val& rhs);
extern  bool operator!=(const scl::den_val& lhs, const scl::den_val& rhs);
extern  std::istream& operator>>(std::istream& is, scl::den_val& dv);
extern  std::ostream& operator<<(std::ostream& os, const scl::den_val& dv);

struct map_val;
  
struct sci_val {               //Order and method of computation:
          sci_val();
          sci_val(const scl::realmat& parm);
          sci_val(const scl::realmat& parm, const map_val& mv);
  scl::realmat sci_mod_parm;   // assigned
  bool    sci_mod_support;     // sci_mod support method
  bool    sci_mod_simulate;    // sci_mod gen_sim method
  scl::realmat sci_mod_func;   // sci_mod gen_sim method
  scl::den_val sci_mod_prior;  // sci_mod prior method
  scl::realmat stat_mod_parm;  // stat_mcmc, no priors, stat_mod.data=sci_sim
  scl::den_val stat_mod_sub_logl; // stat_mcmc, no priors, stat_mod.data=sci_sim
  scl::den_val stat_mod_logl;  // stat_mod logl method, stat_mod.data=data
  bool    stat_mod_support;    // stat_mod support method,  for line above and
  bool    stat_mod_simulate;   // stat_mod gen_sim method   all following
  scl::realmat stat_mod_func;  // stat_mod gen_sim method   stat_mod.parm is
  scl::den_val stat_mod_prior; // stat_mod_prior method     mode.stat_mod_parm
  std::string annotated_sci_val() const;
  friend  std::istream& operator>>(std::istream& is, sci_val& scv);
  friend  std::ostream& operator<<(std::ostream& os, const sci_val& scv);
};

extern scl::realmat pack_sci_val(const sci_val& sv);
extern sci_val unpack_sci_val(const scl::realmat& rm); 

struct map_val {
          map_val();
          map_val(const sci_val& sv);
  bool    sci_mod_support;
  bool    sci_mod_simulate;
  scl::realmat sci_mod_func;
  scl::den_val sci_mod_prior;
  scl::realmat stat_mod_parm;
  scl::den_val stat_mod_sub_logl;
  scl::den_val stat_mod_logl;
  bool    stat_mod_support;
  bool    stat_mod_simulate;
  scl::realmat stat_mod_func;
  scl::den_val stat_mod_prior;
  friend  bool operator==(const map_val& lhs, const map_val& rhs);
  friend  bool operator!=(const map_val& lhs, const map_val& rhs);
};

bool near_eq(REAL lhs, REAL rhs, REAL tol=1.e-5);
bool near_eq(scl::den_val lhs, scl::den_val rhs, REAL tol=1.e-5);
bool near_eq(const scl::realmat& lhs, const scl::realmat& rhs, REAL tol=1.e-5);
bool near_eq(const map_val& lhs, const map_val& rhs, REAL tol=1.e-5);

struct stat_val {
  scl::realmat stat_mod_parm;        
  scl::den_val stat_mod_logl;
  bool    stat_mod_support;
  bool    stat_mod_simulate;
  scl::realmat stat_mod_func;
  scl::den_val stat_mod_prior;
  scl::den_val assess_prior;
  friend  std::istream& operator>>(std::istream& is, stat_val& stv);
  friend  std::ostream& operator<<(std::ostream& os, const stat_val& stv);
};

extern scl::realmat pack_stat_val(const stat_val& sv);
extern stat_val unpack_stat_val(const scl::realmat& rm); 

struct prop_group {
  REAL    freq;   // Relative probability of choosing this group
  scl::intvec  gvec; // Contains indexes of group members 
  scl::realmat ginc; 
    // Increment of group, must be (fractional) powers of two.
  scl::realmat mean;   
    // Mean vector of group, not used by random walk props.
  scl::realmat Vmat; // Variance matrix of group
  prop_group() : freq(1), gvec(), ginc(), Vmat() { }
  prop_group(REAL f, const scl::intvec& gv, const scl::realmat& gi, 
     const scl::realmat& u, const scl::realmat& V)
   : freq(f), gvec(gv), ginc(gi), mean(u), Vmat(V) { }
};

typedef std::vector<prop_group> prop_def;

class proposal_base {
public:
  virtual scl::den_val operator()(const scl::realmat& p_old, 
    const scl::realmat& p_new)=0;
  virtual void draw(INT_32BIT& seed, const scl::realmat& p_old, 
    scl::realmat& p_new)=0;
  virtual INTEGER len_parm()=0;
  virtual bool transition_is_symmetric() { return false; }
  virtual ~proposal_base() {};
};

class sci_mod_base {
public:
  virtual INTEGER len_parm() = 0;
  virtual INTEGER len_func() = 0;
  virtual void get_parm(scl::realmat& parm) = 0;
  virtual void set_parm(const scl::realmat& parm) = 0;
  virtual bool support(const scl::realmat& parm) = 0;
  virtual scl::den_val prior(const scl::realmat& parm, 
    const scl::realmat& func) = 0;
  virtual bool gen_sim(scl::realmat& sim, scl::realmat& func) = 0;
  virtual ~sci_mod_base() { }
};

class stat_mod_base {
public:
  virtual INTEGER len_parm() = 0;
  virtual INTEGER len_func() = 0;
  virtual INTEGER num_obs(); 
  virtual void get_parm(scl::realmat& parm) = 0;
  virtual void set_parm(const scl::realmat& parm) = 0;
  virtual void set_data_ptr(const scl::realmat* data_ptr) = 0;
  virtual bool support(const scl::realmat& parm) = 0;
  virtual scl::den_val prior(const scl::realmat& parm, 
    const scl::realmat& func) = 0;
  virtual bool gen_sim(scl::realmat& sim, scl::realmat& func) = 0;
  virtual scl::den_val loglikelihood() = 0;
  virtual scl::den_val loglikelihood(scl::realmat& dlogl);
  virtual REAL penalty(scl::realmat& dpenalty);
  virtual INTEGER mle(scl::realmat& stat_parm_mle, scl::realmat& stat_parm_V);
  virtual ~stat_mod_base() { }
};

class stat_mod_eqns : public scl::nleqns_base {
  private:
    stat_mod_base& stat_mod;
  public:
    stat_mod_eqns(stat_mod_base& stmod) : stat_mod(stmod) { }
    bool get_f(const scl::realmat& parm, scl::realmat& f);
    bool get_F(const scl::realmat& parm, scl::realmat& f, 
      scl::realmat& F);
};

}

#endif
