/*-------------------------------------------------------------------------------------*/
/*  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               */
/*-------------------------------------------------------------------------------------*/
#include "Variable_Group.hpp"
using namespace std;

/*---------------------------------------------------------*/
/*                     comparison operator                 */
/*---------------------------------------------------------*/
bool Variable_Group::operator < ( const Variable_Group & vg ) const {
  if ( _var_indexes.size() < vg._var_indexes.size() )
    return true;
  if ( _var_indexes.size() > vg._var_indexes.size() )
    return false;
  set<int>::const_iterator end = _var_indexes.end() , it2 = vg._var_indexes.begin();
  for ( set<int>::const_iterator it1 = _var_indexes.begin() ;
	it1 != end ; ++it1 , ++it2 ) {
    if ( *it1 < *it2 )
      return true;
    if ( *it1 > *it2 )
      return false;
  }
  return false;
}

/*-------------------------------------------------------------*/
/*                             checks                          */
/*-------------------------------------------------------------*/
/*  . invoked by Signature::init() with dir_types              */
/*                                      == sec_poll_dir_types  */
/*                                      == barrier_type        */
/*                                      == in_group            */
/*                                      == NULL                */
/*                                                             */
/*  . invoked by Parameters::check() with all parameters       */
/*-------------------------------------------------------------*/
bool Variable_Group::check ( const Point                 & fixed_vars         ,
			     const vector<bb_input_type> & bbit               ,
			     const set<direction_type>   * dir_types          ,
			     const set<direction_type>   * sec_poll_dir_types ,
			     const bb_output_type        * barrier_type       ,
			     vector<bool>                * in_group             ) {

  // additional initializations for _directions:
  if ( dir_types && sec_poll_dir_types && barrier_type )
    _directions.init ( *dir_types , *sec_poll_dir_types , *barrier_type );

  // initial checks:
  if ( _var_indexes.empty() )
    return false;
    
  bool binary      = true;
  bool categorical = false;

  // other checks + filling of vector in_group:
  int                      n        = static_cast<int>(bbit.size());
  set<int>::const_iterator end      = _var_indexes.end();
  for ( set<int>::const_iterator it = _var_indexes.begin() ; it != end ; ++it ) {
    if ( *it < 0                       ||
	 *it >= n                      ||
	 fixed_vars[*it].is_defined()     )
      return false;

    if ( bbit[*it] == _CATEGORICAL_ ) {
      categorical = true;
      binary      = false;
    }
    else {
      if ( categorical )
	return false;
      if ( bbit[*it] != _BINARY_ )
	binary = false;
    }

    if (in_group)
      (*in_group)[*it] = true;
  }

  if ( binary )
    _directions.set_binary();
  else {

    // we check here that _GPS_BINARY_ is not in dir_types nor in sec_poll_dir_types:
    if ( dir_types && sec_poll_dir_types &&
	 ( dir_types->find         (_GPS_BINARY_) != dir_types->end()          ||
	   sec_poll_dir_types->find(_GPS_BINARY_) != sec_poll_dir_types->end()    ) )
      return false;

    if ( categorical )
      _directions.set_categorical();
  }

  return true;
}

/*---------------------------------------------------------*/
/*                          display                        */
/*---------------------------------------------------------*/
void Variable_Group::display ( ostream & out ) const {
  out << "{ ";
  set<int>::const_iterator end = _var_indexes.end();
  for ( set<int>::const_iterator it = _var_indexes.begin() ; it != end ; ++it )
    out << *it << " ";
  out << "}, dirs={ " << _directions << " }";
}
