/*-------------------------------------------------------------------------------------*/
/*  NOMAD - Nonsmooth Optimization by Mesh Adaptive Direct search - version 3.0.0      */
/*                                                                                     */
/*  Copyright (C) 2001-2008  Mark Abramson        - the Boeing Company, Seattle        */
/*                           Charles Audet        - Ecole Polytechnique, Montreal      */
/*                           Gilles Couture       - Ecole Polytechnique, Montreal      */
/*                           John Dennis          - Rice University, Houston           */
/*                           Sebastien Le Digabel - Ecole Polytechnique, Montreal      */
/*                                                                                     */
/*  funded in part by AFOSR and Exxon Mobil                                            */
/*                                                                                     */
/*  Author: Sebastien Le Digabel                                                       */
/*                                                                                     */
/*  Contact information:                                                               */
/*    Ecole Polytechnique de Montreal - GERAD                                          */
/*    C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada                  */
/*    e-mail: Sebastien.Le.Digabel@gerad.ca                                            */
/*    phone : 1-514-340-6053 #6673                                                     */
/*    fax   : 1-514-340-5665                                                           */
/*                                                                                     */
/*  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 3 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, see <http://www.gnu.org/licenses/>.                               */
/*                                                                                     */
/*  You can find information on the NOMAD software at www.gerad.ca/nomad               */
/*-------------------------------------------------------------------------------------*/
#ifndef __PARAMETERS__
#define __PARAMETERS__

#include <algorithm>
#include <fstream>
#include <ctime>
#include <map>
#include "Parameter_Entries.hpp"
#include "Variable_Group.hpp"

class Parameters : private Uncopyable {

private:
  
  bool           _to_be_checked;  // access control to the parameters.
  std::ostream & _out;            // internal displays

  // initializations:
  void init (void);

  // converting a string into a bb_output_type:
  static bool get_bb_output_type ( const std::string & s , bb_output_type & bbot );

  // converting a string into a hnorm_type:
  static bool get_hnorm_type ( const std::string & s , hnorm_type & hn );

  // interpretation of the entries for x0:
  void interpret_x0 ( const Parameter_Entries & entries );

  // interpretation of the Parameter_Entry for mesh/poll sizes:
  void interpret_mesh_sizes ( const Parameter_Entries & entries    ,
			      const std::string       & param_name   );


  // interpretation of the Parameter_Entry for bounds and fixed variables:
  void interpret_bounds_and_fixed_vars ( const Parameter_Entries & entries    ,
					 const std::string       & param_name   );

  // interpretation of the Parameter_Entry for BB_INPUT_TYPE:
  void interpret_bb_input_type ( const Parameter_Entries & entries );

  // interpretation of the Parameter_Entry for VARIABLE_GROUP:
  void interpret_var_groups ( const Parameter_Entries & entries );

  // delete the list of x0 points:
  void delete_x0s ( void );

  // check a directory name:
  static bool check_directory ( std::string & dir );

  // add seed to a file name:
  static void add_seed_to_file_name ( int            n_seed    ,
				      const string & sseed    ,
				      string       & file_name   );

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

public:

  // exception class for a wrong parameters file:
  class Wrong_Parameters_File : public NOMAD::Exception {
  public:
    Wrong_Parameters_File ( const std::string & file ,
			    int                 line ,
			    const std::string & msg) : //  = "wrong parameters file" ) :
      NOMAD::Exception ( file , line , msg ) {}
  };

  // exception class for an incorrect parameter:
  class Incorrect_Parameter : public NOMAD::Exception {
  public:
    Incorrect_Parameter ( const std::string & file ,
			  int                 line ,
			  const std::string & msg    ) :
      NOMAD::Exception ( file , line , msg ) {}
  };

  // exception class for a bad access:
  class Bad_Access : public NOMAD::Exception {
  public:
    Bad_Access ( const std::string & file ,
		 int                 line ,
		 const std::string & msg    ) :
      NOMAD::Exception ( file , line , msg ) {}
  };

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

  // constructor:
  explicit Parameters ( std::ostream & out = std::cout );

  // destructor:
  ~Parameters ( void );

  // reset:
  void reset ( void ) { init(); }

  // reading a parameters file:
  void read ( const std::string & param_file );

  // checking the parameters:
  void check ( bool remove_history_file = true );

  // display:
  void display ( std::ostream & out ) const;
  void display ( void               ) const { display(_out); }
  
  /*----------------------------------------------------------------------*/
  /*           Parameters attributes: Methods listed by categories        */
  /*----------------------------------------------------------------------*/

  // algorithm and misc parameters:
  // ------------------------------
private:
  std::string            _problem_dir;
  std::string            _tmp_dir;
  int                    _seed;
  int                    _display_degree;
  int                    _poll_display_degree;
  int                    _search_display_degree;
  int                    _updates_display_degree;
  std::list<std::string> _display_stats;
  int                    _max_eval;
  int                    _max_bb_eval;
  int                    _max_sim_bb_eval;
  int                    _max_time;
  int                    _max_iterations;
  NOMAD::Double          _f_target;
  NOMAD::Double          _stat_sum_target;
  bool                   _snap_to_bounds;

public:

  const std::list<std::string> & get_display_stats          ( void ) const;
  int                            get_display_degree         ( void ) const;
  int                            get_poll_display_degree    ( void ) const;
  int                            get_search_display_degree  ( void ) const;
  int                            get_updates_display_degree ( void ) const;
  int                            get_seed                   ( void ) const;
  int                            get_max_eval               ( void ) const;
  int                            get_max_sim_bb_eval        ( void ) const;
  int                            get_max_bb_eval            ( void ) const;
  int                            get_max_time               ( void ) const;
  int                            get_max_iterations         ( void ) const;
  const NOMAD::Double &          get_f_target               ( void ) const;
  const NOMAD::Double &          get_stat_sum_target        ( void ) const;
  const std::string   &          get_problem_dir            ( void ) const;
  const std::string   &          get_tmp_dir                ( void ) const;
  bool                           get_snap_to_bounds         ( void ) const;

  void set_EPSILON             ( const NOMAD::Double          & );
  void set_POINT_DISPLAY_LIMIT ( int                            );
  void set_DISPLAY_STATS       ( const std::list<std::string> & );
  bool set_DISPLAY_DEGREE      ( int                            );
  bool set_DISPLAY_DEGREE      ( const std::string            & );
  void set_SEED                ( int                            );
  void set_MAX_EVAL            ( int                            );
  void set_MAX_SIM_BB_EVAL     ( int                            );
  void set_MAX_BB_EVAL         ( int                            );
  void set_MAX_TIME            ( int                            );
  void set_MAX_ITERATIONS      ( int                            );
  void set_F_TARGET            ( const NOMAD::Double          & );
  void set_STAT_SUM_TARGET     ( const NOMAD::Double          & );
  void set_PROBLEM_DIR         ( const std::string            & );
  void set_TMP_DIR             ( const std::string            & );
  void set_SNAP_TO_BOUNDS      ( bool                           );

  // Output files:
  // -------------
private:
  std::list<std::string> _stats_file;
  std::string            _stats_file_name;
  bool                   _add_seed_to_file_names;
  std::string            _solution_file;
  std::string            _history_file;
  std::string            _cache_file;
  int                    _cache_save_period;

public:
  const std::list<std::string> & get_stats_file        ( void ) const;
  const std::string            & get_stats_file_name   ( void ) const;
  const std::string            & get_solution_file     ( void ) const;
  const std::string            & get_history_file      ( void ) const;
  const std::string            & get_cache_file        ( void ) const;
  int                            get_cache_save_period ( void ) const;

  void                  reset_stats_file           ( void );
  void                  set_STATS_FILE             ( const std::string            & file_name ,
						     const std::list<std::string> & stats       );
  void                  set_STATS_FILE             ( const std::string            & file_name ,
						     const std::string            & stats       );

  void                  set_ADD_SEED_TO_FILE_NAMES ( bool                           );
  void                  set_SOLUTION_FILE          ( const std::string &            );
  void                  set_HISTORY_FILE           ( const std::string &            );
  void                  set_CACHE_FILE             ( const std::string &            );
  void                  set_CACHE_SAVE_PERIOD      ( int                            );

  // Searches:
  // ---------
private:

  bool _speculative_search;
  int  _LH_search_p0;
  int  _LH_search_pi;

public:
  bool get_speculative_search ( void ) const;
  int  get_LH_search_p0       ( void ) const;
  int  get_LH_search_pi       ( void ) const;

  void set_SPECULATIVE_SEARCH ( bool );
  void set_LH_SEARCH          ( int , int );

  // Mesh:
  // -----
private:

  NOMAD::Double _mesh_update_basis;         // mesh update basis (tau)
  int           _mesh_coarsening_exponent;  // mesh coarsening exponent
  int           _mesh_refining_exponent;    // mesh refining exponent
  int           _initial_mesh_index;        // initial mesh index (l0)
  int           _max_mesh_index;            // final mesh index   (lmax)
  Point         _initial_mesh_size;         // initial (absolute) mesh size (delta^m_0  )
  Point         _min_mesh_size;             // minimal (absolute) mesh size (delta^m_min)
  Point         _min_poll_size;             // minimal (absolute) poll size (delta^p_min)
public:
  const NOMAD::Double & get_mesh_update_basis        ( void ) const;
  int                   get_mesh_coarsening_exponent ( void ) const;
  int                   get_mesh_refining_exponent   ( void ) const;
  int                   get_initial_mesh_index       ( void ) const;
  int                   get_max_mesh_index           ( void ) const;
  const Point         & get_initial_mesh_size        ( void ) const;
  const Point         & get_min_mesh_size            ( void ) const;
  const Point         & get_min_poll_size            ( void ) const;

  void set_MAX_MESH_INDEX           ( int                   lmax );
  void set_MESH_UPDATE_BASIS        ( const NOMAD::Double & tau  );
  void set_INITIAL_MESH_INDEX       ( int                   l0   );
  void set_MESH_REFINING_EXPONENT   ( int                   mre  );
  void set_MESH_COARSENING_EXPONENT ( int                   mce  );

  void set_MIN_MESH_SIZE     ( const NOMAD::Double             & , bool relative = false );
  void set_MIN_MESH_SIZE     ( int index , const NOMAD::Double & , bool relative = false );
  void set_MIN_MESH_SIZE     ( const Point                     & , bool relative = false );

  void set_MIN_POLL_SIZE     ( const NOMAD::Double             & , bool relative = false );
  void set_MIN_POLL_SIZE     ( int index , const NOMAD::Double & , bool relative = false );
  void set_MIN_POLL_SIZE     ( const Point                     & , bool relative = false );

  void set_INITIAL_MESH_SIZE ( const NOMAD::Double             & , bool relative = false );
  void set_INITIAL_MESH_SIZE ( int index , const NOMAD::Double & , bool relative = false );
  void set_INITIAL_MESH_SIZE ( const Point                     & , bool relative = false );

  // Directions:
  // -----------
private:
  std::set<direction_type> _direction_types;    // types of directions
  std::set<direction_type> _sec_poll_dir_types; // types of directions for the secondary poll
  int                      _halton_seed;        // Halton seed for the Ortho-MADS directions
                                                // (if def. to -1, will be set in Directions)
public:
  const std::set<direction_type> & get_direction_types         ( void ) const;
  const std::set<direction_type> & get_sec_poll_dir_types      ( void ) const;
  int                              get_halton_seed             ( void ) const;  

  void                             set_DIRECTION_TYPE          ( direction_type );
  void                             set_SEC_POLL_DIRECTION_TYPE ( direction_type );
  void                             set_HALTON_SEED             ( int            );    

  // X0:
  // ---
private:
  std::vector<Point *> _x0s;            // list of x0 points
  std::string          _x0_cache_file;  // cache containing starting points

public:
  void set_X0   ( const Point       & x0        );  // add a new point in _x0s
  void set_X0   ( const std::string & file_name );  // indicate a cache file

  void reset_X0 ( void                          );  // reset parameter X0

  const std::vector<Point *> & get_x0s           ( void ) const;
  const std::string          & get_x0_cache_file ( void ) const;

  // DIMENSION:
  // ----------
private:
  int _dimension;   // dimension (n)
public:
  int  get_dimension (void) const;
  bool set_DIMENSION (int dim);

  // FIXED-VARIABLES:
  // ----------------
private:
  Point _fixed_variables;
public:
  const Point & get_fixed_variables (void) const;
  void set_FIXED_VARIABLE  ( int index , const NOMAD::Double & value );

  // variable groups:
  // ----------------
private:
  
  std::set<Variable_Group * , VG_Comp> _var_groups;
  std::set<Variable_Group * , VG_Comp> _user_var_groups;

  // reset variable groups:
  void reset_variable_groups ( std::set<Variable_Group *,VG_Comp> & ) const;

public:

  const std::set<Variable_Group *,VG_Comp> & get_variable_groups ( void ) const;

  void set_VARIABLE_GROUP ( const std::set<int>            & var_indexes         ,
			    const std::set<direction_type> & prim_poll_dir_types ,
			    const std::set<direction_type> & sec_poll_dir_types  ,
			    int                              halton_seed           );

  // BOUNDS:
  // -------
private:
  Point _lb;
  Point _ub;
public:
  const Point & get_lb  (void) const;
  const Point & get_ub  (void) const;
  void  set_LOWER_BOUND ( int index , const NOMAD::Double & value);
  void  set_LOWER_BOUND ( const Point & );
  void  set_UPPER_BOUND ( int index , const NOMAD::Double & value);
  void  set_UPPER_BOUND ( const Point & );

  // BLACK-BOXES (inputs and outputs):
  // ---------------------------------
private:

  // inputs:
  bool                       _all_continuous;
  std::vector<bb_input_type> _bb_input_types;
  std::list<int>             _index_obj;
  bool                       _bb_input_include_tag;
  bool                       _bb_input_include_seed;

  // outputs:
  mutable std::vector<bb_output_type> _bb_output_types;  // can be modified during the algo.
                                                         // (PEB constraints)

  std::list<std::string>              _bb_exe;           // list of black-box executables

  int                                 _index_stat_sum;   // indexes of outputs
  int                                 _index_stat_avg;   // STAT_SUM or STAT_AVG

  bool                                _bb_redirection;

public:
  int                                 get_bb_nb_outputs         ( void ) const;
  bool                                get_bb_input_include_tag  ( void ) const;
  bool                                get_bb_input_include_seed ( void ) const;
  const std::vector<bb_input_type>  & get_bb_input_types        ( void ) const;
  const std::vector<bb_output_type> & get_bb_output_types       ( void ) const;
  const std::list<int>              & get_index_obj             ( void ) const;
  bool                                check_stat_sum            ( void ) const;
  bool                                check_stat_avg            ( void ) const;
  int                                 get_index_stat_sum        ( void ) const;
  int                                 get_index_stat_avg        ( void ) const;
  const std::list<std::string>      & get_bb_exe                ( void ) const;
  bool                                get_bb_redirection        ( void ) const;

  void  set_BB_INPUT_INCLUDE_TAG  ( bool                                      );
  void  set_BB_INPUT_INCLUDE_SEED ( bool                                      );
  void  set_BB_INPUT_TYPE         ( int index , bb_input_type           bbit  );
  void  set_BB_OUTPUT_TYPE        ( const std::list  <bb_output_type> & bbot  );
  void  set_BB_OUTPUT_TYPE        ( const std::vector<bb_output_type> & bbot  );
  void  set_BB_EXE                ( const std::list<std::string>      & bbexe );
  void  set_BB_EXE                ( int m , const std::string         * bbexe );
  void  set_BB_EXE                ( const std::string                 & bbexe );
  void  set_BB_REDIRECTION        ( bool                                      );

  void  reset_PEB_changes            ( void      ) const;
  void  change_PEB_constraint_status ( int index ) const;

  // surrogates:
  // -----------
private:
  std::map<std::string,std::string>   _sgte_exe;         // surrogate executables:
                                                         // (sgte_exe[bb_name] = sgte_name)

  bool                                _sgte_eval_sort;   // if surrogates are used to sort
                                                         // evaluation points

  int                                 _sgte_cost;        // how many surrogate evaluations
                                                         // count as one black-box evaluation

  int                                 _sgte_max_eval;    // max. number of sgte evaluations

  std::string                         _sgte_cache_file;  // surrogate cache file

public:

  std::string          get_sgte_exe        ( const std::string & bb_exe ) const;
  bool                 get_sgte_eval_sort  ( void                       ) const;
  int                  get_sgte_cost       ( void                       ) const;
  int                  get_max_sgte_eval   ( void                       ) const;
  const std::string  & get_sgte_cache_file ( void                       ) const;
  bool                 has_surrogates      ( void ) const {
    return !_sgte_exe.empty();
  }

  void set_SGTE_EXE        ( const std::string & bb_exe , const std::string & sgte_exe );
  void set_SGTE_EVAL_SORT  ( bool                );
  void set_SGTE_COST       ( int                 );
  void set_MAX_SGTE_EVAL   ( int                 );
  void set_SGTE_CACHE_FILE ( const std::string & );

  // BARRIER:
  // --------
private:
  NOMAD::Double  _h_min;
  NOMAD::Double  _h_max_0;
  NOMAD::Double  _rho;
  hnorm_type     _h_norm;

  bool           _has_constraints;
  bool           _has_filter_constraints; // Filter or PB
  bb_output_type _barrier_type;           // _F_ or _PB_ or _PEB_P_ or _EB_

public:
  const NOMAD::Double & get_h_min           ( void ) const;
  const NOMAD::Double & get_h_max_0         ( void ) const;
  const NOMAD::Double & get_rho             ( void ) const;
  hnorm_type            get_h_norm          ( void ) const;
  bb_output_type        get_barrier_type    ( void ) const;
  bool                  use_sec_poll_center ( void ) const;

  void set_H_MIN   ( const NOMAD::Double & h_min  );
  void set_H_MAX_0 ( const NOMAD::Double & h_max  );
  void set_RHO     ( const NOMAD::Double & rho    );
  void set_H_NORM  ( hnorm_type            h_norm );

  // opportunistic strategy parameters:
  // ----------------------------------

private:
  bool          _opportunistic_eval;           // opportunistic strategy considered or not
  int           _opportunistic_min_nb_success; // minimum number of successes
  int           _opportunistic_min_eval;       // minimum number of evaluations
  NOMAD::Double _opportunistic_min_f_imprvmt;  // minimum (rel.) % of feasible obj. improvement
  bool          _opportunistic_lucky_eval;     // lucky evaluation: do one more eval. for luck

public:
  bool                  get_opportunistic_eval           ( void ) const;
  int                   get_opportunistic_min_nb_success ( void ) const;
  int                   get_opportunistic_min_eval       ( void ) const;
  const NOMAD::Double & get_opportunistic_min_f_imprvmt  ( void ) const;
  bool                  get_opportunistic_lucky_eval     ( void ) const;
  
  void set_OPPORTUNISTIC_EVAL           ( bool                  );
  void set_OPPORTUNISTIC_MIN_NB_SUCCESS ( int                   );
  void set_OPPORTUNISTIC_MIN_EVAL       ( int                   );
  void set_OPPORTUNISTIC_MIN_F_IMPRVMT  ( const NOMAD::Double & );
  void set_OPPORTUNISTIC_LUCKY_EVAL     ( bool                  );
};

// display:
inline std::ostream & operator << ( std::ostream & out , const Parameters & p ) {
  p.display(out);
  return out;
}

#endif
