/*-------------------------------------------------------------*/
void NOMAD::Speculative_Search::search ( NOMAD::Mads              & mads           ,
					 int                      & nb_search_pts  ,
					 bool                     & stop           ,
					 NOMAD::stop_type         & stop_reason    ,
					 NOMAD::success_type      & success        ,
					 bool                     & count_search   ,
					 const NOMAD::Eval_Point *& new_feas_inc   ,
					 const NOMAD::Eval_Point *& new_infeas_inc   )
{
  // new_feas_inc and new_infeas_inc are used as inputs,
  // so do not initialize them to NULL here

  nb_search_pts = 0;
  success       = NOMAD::UNSUCCESSFUL;
  count_search  = !stop;

  if ( stop )
    return;
  
  const NOMAD::Display    & out = _p.out();
  NOMAD::dd_type display_degree = out.get_search_dd();
  if ( display_degree == NOMAD::FULL_DISPLAY ) {
    std::ostringstream oss;
    oss << NOMAD::SPEC_SEARCH;
    out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl;
  }

  int                       lkm1;  // l_{k-1}
  int                       lk;    // l_k
  int                       n;
  NOMAD::Signature        * signature;
  NOMAD::Point              delta_m_k;
  NOMAD::Point              delta_m_km1;
  NOMAD::Point              factor;
  NOMAD::Point              xkm1;
  NOMAD::Eval_Point       * sk;
  const NOMAD::Eval_Point * x[2];
  x[0] = new_feas_inc;
  x[1] = new_infeas_inc;
  
  // Evaluator_Control:
  NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control();

  for ( int i = 0 ; i < 2 ; ++i ) {    
    if ( x[i] && x[i]->get_mesh_index() ) {

      const NOMAD::Direction * dir = x[i]->get_direction();
      if ( dir && ( dir->is_mads() || dir->get_type()==NOMAD::MODEL_SEARCH_DIR ) ) {

	// get the x_k's signature:
	signature = x[i]->get_signature();
	if ( !signature )
	  throw NOMAD::Exception ( "Speculative_Search.cpp" , __LINE__ ,
	  "Speculative_Search::search(): could not get the signature" );
      
	xkm1 = *x[i] - *dir;
      
	lk = lkm1 = *x[i]->get_mesh_index();
	NOMAD::Mesh::update ( NOMAD::FULL_SUCCESS , lk );
      
	n           = signature->get_n();
	delta_m_k   = NOMAD::Point ( n );
	delta_m_km1 = NOMAD::Point ( n );
	factor      = NOMAD::Point ( n );

	signature->get_mesh().get_delta_m ( delta_m_k   , lk   );
	signature->get_mesh().get_delta_m ( delta_m_km1 , lkm1 );
      
	// multiplicative factor: takes into account the fact that
	// the direction contains \Delta^m_k:
	try {

	  // factor = delta_m_k / delta_m_km1 :
	  for ( int k = 0 ; k < n ; ++k ) {
	    if ( delta_m_k[k].is_defined()   && delta_m_km1[k].is_defined() &&
		 delta_m_k[k].value() != 0.0 && delta_m_km1[k].value() != 0.0 )
	      factor[k] = delta_m_k[k] / delta_m_km1[k];
	    else
	      factor[k] = 0.0;
	  }
	}
	catch ( NOMAD::Double::Invalid_Value & ) {
	  if ( display_degree == NOMAD::FULL_DISPLAY )
	    out << "could not compute " << _type << " point: stop" << std::endl
		<< NOMAD::close_block ( "end of speculative search" );
	  stop        = true;
	  stop_reason = NOMAD::MESH_PREC_REACHED;
	  return;
	}
      
	if ( lkm1 <= 0 )
	  factor *= NOMAD::Mesh::get_mesh_update_basis();
      
	// speculative search point:
	NOMAD::Direction new_dir ( n , 0.0 , dir->get_type() );
	new_dir.Point::operator = ( factor * *dir );
      
	sk = new NOMAD::Eval_Point;
	sk->set ( n , _p.get_bb_nb_outputs() );
	sk->set_signature  ( signature );
	sk->set_direction  ( &new_dir );
	sk->set_mesh_index ( &lk );
      
	sk->Point::operator = ( xkm1 + new_dir );

	if ( display_degree == NOMAD::FULL_DISPLAY ) {
	  out << "trial point #" << sk->get_tag()
	      << ": ( ";
	  sk->Point::display ( out ," " , 2 , NOMAD::Point::get_display_limit() );
	  out << " )" << std::endl;
	}
      
	// add the new point to the list of search trial points:
	ev_control.add_eval_point ( sk                      ,
				    display_degree          ,
				    _p.get_snap_to_bounds() ,
				    NOMAD::Double()         ,
				    NOMAD::Double()         ,
				    NOMAD::Double()         ,
				    NOMAD::Double()           );
      }
    }
  }
  
  nb_search_pts = ev_control.get_nb_eval_points();
  
  // eval_list_of_points:
  // --------------------
  new_feas_inc = new_infeas_inc = NULL;

  ev_control.eval_list_of_points ( _type                   ,
				   mads.get_true_barrier() ,
				   mads.get_sgte_barrier() ,
				   mads.get_pareto_front() ,
				   stop                    ,
				   stop_reason             ,
				   new_feas_inc            ,
				   new_infeas_inc          ,
				   success                   );

  if ( display_degree == NOMAD::FULL_DISPLAY ) {
    std::ostringstream oss;
    oss << "end of speculative search (" << success << ")";
    out << NOMAD::close_block ( oss.str() ) << std::endl;
  }
}
/*-----------------------------------------------------------*/
void NOMAD::LH_Search::search ( NOMAD::Mads              & mads           ,
                               int                      & nb_search_pts  ,
                               bool                     & stop           ,
                               NOMAD::stop_type         & stop_reason    ,
                               NOMAD::success_type      & success        ,
                               bool                     & count_search   ,
                               const NOMAD::Eval_Point *& new_feas_inc   ,
                               const NOMAD::Eval_Point *& new_infeas_inc   )
{
    new_feas_inc = new_infeas_inc = NULL;
    nb_search_pts = 0;
    success       = NOMAD::UNSUCCESSFUL;
    count_search  = !stop;
    
    if ( stop )
        return;
    
    // initial display:
    const NOMAD::Display    & out = _p.out();
    NOMAD::dd_type display_degree = out.get_search_dd();
    if ( display_degree == NOMAD::FULL_DISPLAY )
    {
        std::ostringstream oss;
        oss << NOMAD::LH_SEARCH;
        out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl;
    }
    
    // active barrier:
    const NOMAD::Barrier     & barrier = mads.get_active_barrier();
    
    // Evaluator_Control:
    NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control();
    
    // current incumbents:
    const NOMAD::Eval_Point  * feas_inc   = barrier.get_best_feasible  ();
    const NOMAD::Eval_Point  * infeas_inc = barrier.get_best_infeasible();
    
    // get a reference point and a signature:
    const NOMAD::Eval_Point  * ref       = (feas_inc) ? feas_inc : infeas_inc;
    NOMAD::Signature         * signature = _p.get_signature();
    
    // check the number of points:
    int p = _initial_search ? _p.get_LH_search_p0() : _p.get_LH_search_pi();
    if ( p <= 0 )
    {
        if ( display_degree == NOMAD::FULL_DISPLAY )
        {
            std::ostringstream oss;
            oss << "end of LH " << ( _initial_search ? "initial " : "")
            << "search (number of points <= 0)";
            out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl;
        }
        return;
    }
    
    // no reference point is available (we consider the standard signature):
    if ( !ref )
    {
        
        // it is not sufficient with categorical variables:
        if ( signature->has_categorical() )
        {
            if ( display_degree == NOMAD::FULL_DISPLAY )
            {
                std::ostringstream oss;
                oss << "end of LH " << ( _initial_search ? "initial " : "")
                << "search (no available reference point)";
                out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl;
            }
            return;
        }
    }
    else
        signature = ref->get_signature();
    
    // Change Display stats style
    const std::list<std::string>         old_ds = _p.get_display_stats();
    std::list<std::string>                 ds    = old_ds;
    ds.push_back ( " (LH)" );
    _p.set_DISPLAY_STATS ( ds );
    
    // check the parameters:
    _p.check ( false ,    // remove_history_file  = false
              false ,    // remove_solution_file = false
              false   ); // remove_stats_file    = false
    
    int                      i;
    NOMAD::Eval_Point      * x;
    int                      n          = signature->get_n();
    int                      m          = _p.get_bb_nb_outputs();
    int                      pm1        = p-1;
    
    // mesh size:
    NOMAD::Point delta_max = signature->get_mesh()->get_delta_max ();
    NOMAD::Double delta_i;
    NOMAD::Point  delta;
    if ( !_initial_search )
        signature->get_mesh()->get_delta ( delta );
    
    // fixed variables:
    const NOMAD::Point & fixed_variables = signature->get_fixed_variables();
    
    // bb input types:
    const std::vector<NOMAD::bb_input_type> & bbit = signature->get_input_types();
    
    // bounds:
    const NOMAD::Point & lb = signature->get_lb();
    const NOMAD::Point & ub = signature->get_ub();
    
    // pts contains n points of dimension p: each of these points contains
    // p different values for each variable:
    NOMAD::Point ** pts = new NOMAD::Point * [n];
    
    // creation of p search points:
    for ( int k = 0 ; k < p ; ++k )
    {
        
        x = new NOMAD::Eval_Point ( n , m );
        x->set_signature  ( signature   );
        
        for ( i = 0 ; i < n ; ++i )
        {
            
            if ( k==0 )
            {
                if ( fixed_variables[i].is_defined() )
                    pts[i] = new NOMAD::Point ( p , fixed_variables[i] );
                else if ( bbit[i] == NOMAD::CATEGORICAL )
                {
                    pts[i] = new NOMAD::Point ( p , (*ref)[i] );
                }
                else
                {
                    pts[i] = new NOMAD::Point ( p );

                    if ( !_initial_search )
                        delta_i = delta[i];
                    
                    values_for_var_i ( p               ,
                                      delta_i       ,
                                      delta_max[i]  ,
                                      bbit       [i]  ,
                                      lb         [i]  ,
                                      ub         [i]  ,
                                      *pts       [i]    );
                }
            }
            
            (*x)[i] = (*pts[i])[k];
            
            if ( k == pm1 )
                delete pts[i];
        }
        
        if ( display_degree == NOMAD::FULL_DISPLAY )
        {
            out << "LH point #" << x->get_tag()
            << ": ( ";
            x->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() );
            out << " )" << std::endl;
        }
        
        // add the new point to the ordered list of search trial points:
        ev_control.add_eval_point ( x               ,
                                   display_degree  ,
                                   false           ,  // snap_to_bounds = false
                                   NOMAD::Double() ,
                                   NOMAD::Double() ,
                                   NOMAD::Double() ,
                                   NOMAD::Double()   );
    }
    
    delete [] pts;
    
    nb_search_pts = ev_control.get_nb_eval_points();
    
    // eval_list_of_points:
    // --------------------
    new_feas_inc = new_infeas_inc = NULL;
    ev_control.eval_list_of_points ( _type                   ,
                                    mads.get_true_barrier() ,
                                    mads.get_sgte_barrier() ,
                                    mads.get_pareto_front() ,
                                    stop                    ,
                                    stop_reason             ,
                                    new_feas_inc            ,
                                    new_infeas_inc          ,
                                    success                   );
    
    
    _p.get_display_stats();
    
    // restore stats style
    _p.set_DISPLAY_STATS              ( old_ds                               );
    _p.check ( false ,    // remove_history_file  = false
              false ,    // remove_solution_file = false
              false   ); // remove_stats_file    = false
    
    
    
    // final displays:
    if ( display_degree == NOMAD::FULL_DISPLAY )
    {
        std::ostringstream oss;
        oss << "end of LH search (" << success << ")";
        out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl;
    }
    
}
/*-----------------------------------------------------------------*/
void NOMAD::Cache::update ( NOMAD::Eval_Point       & cache_x ,
                           const NOMAD::Eval_Point & x         ) const
{
    const NOMAD::Point & bbo_x = x.get_bb_outputs();
    
    if ( &cache_x == &x         ||
        !x.is_eval_ok()        ||
        !cache_x.is_in_cache() ||
        bbo_x.empty()          ||
        cache_x != x              )
        return;
    
    // check the eval types:
    if ( x.get_eval_type      () != _eval_type ||
        cache_x.get_eval_type() != _eval_type    )
        throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ ,
                                         "NOMAD::Cache:update(): problem with the eval. types" );
    
    const NOMAD::Point & bbo_cache_x = cache_x.get_bb_outputs();
    int                  m           = bbo_cache_x.size();
    
    _sizeof -= cache_x.size_of();
    
    // if the current point could not evaluate and x did,
    // or if the number of bb outputs is different, we set cache_x = x:
    if ( !cache_x.is_eval_ok() || m != bbo_x.size() )
    {
        cache_x.set_eval_status ( NOMAD::EVAL_OK     );
        cache_x.set_bb_output   ( bbo_x              );
        cache_x.set_signature   ( x.get_signature () );
        cache_x.set_direction   ( x.get_direction () );
        
        _sizeof += cache_x.size_of();
        return;
    }
    
    // we complete _bb_outputs:
    int c1 = 0;
    int c2 = 0;
    
    for ( int i = 0 ; i < m ; ++i ) {
        
        if ( bbo_cache_x[i].is_defined() )
            ++c1;
        
        if ( bbo_x[i].is_defined() )
            ++c2;
        
        if ( !bbo_cache_x[i].is_defined() && bbo_x[i].is_defined() )
            cache_x.set_bb_output ( i , bbo_x[i] );
    }
    
    // the two points are 'eval_ok' and have comparable outputs:
    // we select the best as the one with the more defined bb_outputs:
    if ( c2 > c1 ) {
        cache_x.set_signature  ( x.get_signature () );
        cache_x.set_direction  ( x.get_direction () );
        
    }
    
    _sizeof += cache_x.size_of();
}