/*-------------------------------------------------------------------------------------*/
/*  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 __MADS__
#define __MADS__

#include <csignal>
#include "Evaluator_Control.hpp"

class Mads : private Uncopyable {

private:
 
  static bool        _force_quit;     // forces NOMAD to terminate if ctrl-c is pressed

  Parameters       & _p;              // parameters
  Stats              _stats;          // statistics
  Signature          _std_signature;  // standard signature     
  Evaluator_Control  _ev_control;     // evaluator control
  Barrier            _barrier;        // barrier
  std::ostream     & _out;            // display

  // add an Eval_Point to the list of points to be evaluated
  // (the point is also snapped to bounds):
  void add_eval_point ( std::set<Priority_Eval_Point>  & pts                ,
			Eval_Point                    *& x                  ,
			int                              display_degree     ,
			bool                             snap_to_bounds     ,
			const Direction               *  feas_success_dir   ,
			const Direction               *  infeas_success_dir ,
			const NOMAD::Double           &  f_sgte             ,
			const NOMAD::Double           &  h_sgte               ) const;

  // x0 eval:
  void eval_x0 (  bool & stop , stop_type & stop_reason );

  // one MADS iteration:
  void iteration ( bool              & stop               ,
		   stop_type         & stop_reason        ,
		   Direction         & feas_success_dir   ,
		   Direction         & infeas_success_dir ,
		   const Eval_Point *& new_feas_inc       ,
		   const Eval_Point *& new_infeas_inc       );

  // MADS phase 1 (try to satisfy EB constraints):
  bool phase_one ( bool & stop , stop_type & stop_reason );

  // the search:
  void search ( bool              & stop           ,
		stop_type         & stop_reason    ,
		success_type      & success        ,
		const Eval_Point *& new_feas_inc   ,
		const Eval_Point *& new_infeas_inc   );

  // the poll:
  void poll ( bool              & stop               ,
	      stop_type         & stop_reason        ,
	      success_type      & success            ,
	      Direction         & feas_success_dir   ,
	      Direction         & infeas_success_dir ,
	      const Eval_Point *& new_feas_inc       ,
	      const Eval_Point *& new_infeas_inc       );

  // speculative search:
  void speculative_search ( int                 display_degree ,
			    bool              & stop           ,
			    stop_type         & stop_reason    ,
			    success_type      & success        ,
			    const Eval_Point *& new_feas_inc   ,
			    const Eval_Point *& new_infeas_inc   );

  // Latin-Hypercube (LH) search:
  void LH_search ( bool                initial_search ,
		   const Signature   & signature      ,
		   bool              & stop           ,
		   stop_type         & stop_reason    ,
		   success_type      & success        ,
		   const Eval_Point *& new_feas_inc   ,
		   const Eval_Point *& new_infeas_inc   );

  // LH search: decide p values for the variable i:
  void LH_values_for_var_i ( int                   i           ,
			     int                   p           ,
			     bool                  project     ,
			     const Point         & delta_m     ,
			     const Point         & delta_m_max ,
			     Point               & x             ) const;

  // use the Evaluator_Control object to evaluate a list of points
  // (see Evaluator_Control.hpp for details):
  void eval_list_of_points ( search_type                     search             ,
			     std::set<Priority_Eval_Point> & points             ,
			     bool                          & stop               ,
			     stop_type                     & stop_reason        ,
			     const Eval_Point             *& new_feas_inc       ,
			     const Eval_Point             *& new_infeas_inc     ,
			     success_type                  & success            ,
			     const Direction              *  feas_success_dir   ,
			     const Direction              *  infeas_success_dir   );

  // display mesh and poll sizes for a given signature:
  void display_deltas ( const Signature & s ) const;

  // displays at the beginning of an iteration:
  void display_iteration_begin ( void ) const;

  // displays at the end of an iteration:
  void display_iteration_end ( int                display_degree ,
			       bool               stop           ,
			       stop_type          stop_reason    ,
			       success_type       success        ,
			       const Eval_Point * new_feas_inc   ,
			       const Eval_Point * new_infeas_inc   ) const;

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

public:

  // constructor:
  explicit Mads ( Parameters   & p               ,
		  Evaluator    * ev  = NULL      ,
		  std::ostream & out = std::cout   );

  // destructor:
  ~Mads ( void ) {}

  // algorithm execution:
  stop_type run ( void );

  // force quit (called by pressing ctrl-c):
  static void force_quit ( int signalValue );

  // reset:
  void reset ( bool keep_barrier = false , bool keep_stats = false );

  // display:
  void display ( std::ostream & out ) const;
  void display ( void               ) const { display(_out); }

  // GET methods:

  const Stats & get_stats ( void ) const { return _stats; }

  const Eval_Point * get_best_infeasible ( void ) const {
    return _barrier.get_best_infeasible();
  }

  const Eval_Point * get_best_feasible ( void ) const {
    return _barrier.get_best_feasible();
  }

};

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

#endif
