/*-------------------------------------------------------------------------------------*/
/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */
/* */
/* Copyright (C) 2001-2012 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 */
/* Christophe Tribes - 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: nomad@gerad.ca */
/* phone : 1-514-340-6053 #6928 */
/* fax : 1-514-340-5665 */
/* */
/* This program is free software: you can redistribute it and/or modify it under the */
/* terms of the GNU Lesser 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 Lesser General Public License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License along */
/* with this program. If not, see . */
/* */
/* You can find information on the NOMAD software at www.gerad.ca/nomad */
/*-------------------------------------------------------------------------------------*/
/**
\file Signature.cpp
\brief Evaluation point signature (implementation)
\author Sebastien Le Digabel
\date 2010-04-22
\see Signature.hpp
*/
#include "Signature.hpp"
/*-----------------------------------*/
/* static members initialization */
/*-----------------------------------*/
#ifdef MEMORY_DEBUG
int NOMAD::Signature::_cardinality = 0;
int NOMAD::Signature::_max_cardinality = 0;
#endif
bool NOMAD::Signature::_warning_has_been_displayed=false;
/*--------------------------------------------------*/
/* constructor 1 */
/*--------------------------------------------------*/
NOMAD::Signature::Signature
( int n ,
const std::vector & input_types ,
const NOMAD::Point & initial_mesh_size ,
const NOMAD::Point & min_mesh_size ,
const NOMAD::Point & min_poll_size ,
const NOMAD::Point & lb ,
const NOMAD::Point & ub ,
const NOMAD::Point & scaling ,
const NOMAD::Point & fixed_variables ,
const std::vector & periodic_variables ,
std::set & var_groups ,
const NOMAD::Display & out )
: _mesh ( NULL ) ,
_std ( false ) ,
_out (out)
{
init ( n ,
input_types ,
initial_mesh_size ,
min_mesh_size ,
min_poll_size ,
lb ,
ub ,
scaling ,
fixed_variables ,
periodic_variables ,
var_groups );
#ifdef MEMORY_DEBUG
++NOMAD::Signature::_cardinality;
if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality )
++NOMAD::Signature::_max_cardinality;
#endif
}
/*--------------------------------------------------*/
/* constructor 2 */
/*--------------------------------------------------*/
NOMAD::Signature::Signature
( int n ,
const std::vector & input_types ,
const NOMAD::Point & initial_mesh_size ,
const NOMAD::Point & lb ,
const NOMAD::Point & ub ,
const std::set & direction_types ,
const std::set & sec_poll_dir_types ,
int halton_seed ,
const NOMAD::Display & out )
: _mesh ( NULL ) ,
_std ( false ) ,
_out ( out )
{
if ( static_cast ( input_types.size() ) != n )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::Signature(): bad argument: input_types" );
// automatic creation of groups of variables:
// ------------------------------------------
std::set var_groups;
{
std::set vi_cbi; // list of cont./bin./int. variables
std::set vi_cat; // list of categorical variables
for ( int i = 0 ; i < n ; ++i )
if ( input_types[i] != NOMAD::CATEGORICAL )
vi_cbi.insert(i);
else
vi_cat.insert(i);
// creation of a group for cont./bin./int. variables:
if ( !vi_cbi.empty() )
var_groups.insert ( new NOMAD::Variable_Group ( vi_cbi ,
direction_types ,
sec_poll_dir_types ,
halton_seed++ ,
out ) );
// creation of a group for categorical variables:
if ( !vi_cat.empty() )
var_groups.insert ( new NOMAD::Variable_Group ( vi_cat ,
direction_types ,
sec_poll_dir_types,
-1 , // no Halton seed
out ) );
}
// init:
// -----
init ( n ,
input_types ,
initial_mesh_size ,
NOMAD::Point() ,
NOMAD::Point() ,
lb ,
ub ,
NOMAD::Point() ,
NOMAD::Point() ,
std::vector() ,
var_groups );
// delete the temporary groups of variables:
std::set::iterator
it , end = var_groups.end();
for ( it = var_groups.begin() ; it != end ; ++it )
delete *it;
#ifdef MEMORY_DEBUG
++NOMAD::Signature::_cardinality;
if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality )
++NOMAD::Signature::_max_cardinality;
#endif
}
/*--------------------------------------------------*/
/* copy constructor */
/*--------------------------------------------------*/
NOMAD::Signature::Signature ( const NOMAD::Signature & s )
: _lb ( s._lb ) ,
_ub ( s._ub ) ,
_scaling ( s._scaling ) ,
_fixed_variables ( s._fixed_variables ) ,
_input_types ( s._input_types ) ,
_all_continuous ( s._all_continuous ) ,
_has_categorical ( s._has_categorical ) ,
_periodic_variables ( s._periodic_variables ) ,
_mesh ( new NOMAD::Mesh(*s._mesh) ) ,
_std ( false ) ,
_feas_success_dir ( s._feas_success_dir ) ,
_infeas_success_dir ( s._infeas_success_dir ) ,
_out (s._out)
{
std::list::const_iterator it , end = s._var_groups.end();
for ( it = s._var_groups.begin() ; it != end ; ++it )
_var_groups.push_back ( new NOMAD::Variable_Group(**it) );
#ifdef MEMORY_DEBUG
++NOMAD::Signature::_cardinality;
if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality )
++NOMAD::Signature::_max_cardinality;
#endif
}
/*--------------------------------------------------*/
/* destructor */
/*--------------------------------------------------*/
NOMAD::Signature::~Signature ( void )
{
clear();
#ifdef MEMORY_DEBUG
--NOMAD::Signature::_cardinality;
#endif
}
/*--------------------------------------------------------------------------------*/
/* clear (private method called by destructor and after an exception is thrown) */
/*--------------------------------------------------------------------------------*/
void NOMAD::Signature::clear ( void )
{
delete _mesh;
_mesh = NULL;
_all_continuous = true;
_has_categorical = false;
_std = false;
reset_var_groups();
_feas_success_dir.clear();
_infeas_success_dir.clear();
_lb.clear();
_ub.clear();
_scaling.clear();
_fixed_variables.clear();
_input_types.clear();
_periodic_variables.clear();
}
/*--------------------------------------------------*/
/* feasible success direction */
/*--------------------------------------------------*/
void NOMAD::Signature::set_feas_success_dir ( const NOMAD::Direction & d )
{
if ( d.size() != static_cast(_input_types.size()) )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::set_feas_success_dir(): bad direction" );
_feas_success_dir = d;
}
/*--------------------------------------------------*/
/* infeasible success direction */
/*--------------------------------------------------*/
void NOMAD::Signature::set_infeas_success_dir ( const NOMAD::Direction & d )
{
if ( d.size() != static_cast(_input_types.size()) )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::set_infeas_success_dir(): bad direction" );
_infeas_success_dir = d;
}
/*--------------------------------------------------*/
/* initializations (private) */
/*--------------------------------------------------*/
void NOMAD::Signature::init
( int n ,
const std::vector & input_types ,
const NOMAD::Point & initial_mesh_size ,
const NOMAD::Point & min_mesh_size ,
const NOMAD::Point & min_poll_size ,
const NOMAD::Point & lb ,
const NOMAD::Point & ub ,
const NOMAD::Point & scaling ,
const NOMAD::Point & fixed_variables ,
const std::vector & periodic_variables ,
std::set & var_groups )
{
// reset directions:
_feas_success_dir.clear();
_infeas_success_dir.clear();
// check the dimension (n):
if ( n <= 0 )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): bad argument: n" );
// bounds:
if ( lb.empty() )
_lb.reset ( n );
else if ( lb.size() == n )
_lb = lb;
else
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): bad argument: lb" );
if ( ub.empty() )
_ub.reset ( n );
else if ( ub.size() == n )
_ub = ub;
else
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): bad argument: ub" );
// scaling:
if ( scaling.empty() )
_scaling.reset ( n );
else if ( scaling.size() == n )
_scaling = scaling;
else
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): bad argument: scaling" );
int i;
for ( i = 0 ; i < n ; ++i )
if ( _scaling[i].is_defined() && _scaling[i] == 0.0 )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): bad argument: scaling (zero value)" );
// fixed variables:
if ( fixed_variables.empty() )
_fixed_variables.reset ( n );
else if ( fixed_variables.size() == n )
_fixed_variables = fixed_variables;
else
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): bad argument: fixed_variables" );
// periodic variables:
_periodic_variables = periodic_variables;
if ( !_periodic_variables.empty() ) {
if ( static_cast(periodic_variables.size()) != n )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): bad argument: periodic_variables" );
for ( i = 0 ; i < n ; ++i )
if ( _periodic_variables[i] && ( !_lb[i].is_defined() || !_ub[i].is_defined() ) )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): incompatible periodic variables" );
}
// input types:
if ( static_cast(input_types.size()) != n )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): bad argument: input_types" );
_input_types = input_types;
_all_continuous = true;
_has_categorical = false;
for ( i = 0 ; i < n ; ++i )
{
if ( (_lb[i].is_defined() || _ub[i].is_defined() ) && _input_types[i] == NOMAD::CATEGORICAL && _out.get_gen_dd()>=NOMAD::NORMAL_DISPLAY && !_warning_has_been_displayed )
{
_out << NOMAD::open_block("Warning:")
<< "NOMAD::Signature::init(): Providing bounds for categorical variables is not recommended!" << std::endl
<< NOMAD::close_block();
_warning_has_been_displayed=true;
}
if ( _fixed_variables[i].is_defined() && ((_lb[i].is_defined() && _fixed_variables[i] < _lb[i]) || (_ub[i].is_defined() && _fixed_variables[i] > _ub[i]) ||
( (_input_types[i] == NOMAD::INTEGER || _input_types[i] == NOMAD::CATEGORICAL )
&& !_fixed_variables[i].is_integer() ) ||
( _input_types[i] == NOMAD::BINARY && !_fixed_variables[i].is_binary() ) ) )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): bad argument: fixed variable inconsistent with bounds or input types" );
if ( _lb[i].is_defined() && _ub[i].is_defined() )
{
if ( _lb[i].is_defined() && _ub[i].is_defined() && _lb[i].value()> ub[i].value() )
{
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): bad argument: lower bound must be lower than upper bound!" );
}
if ( _lb[i] == _ub[i] )
_fixed_variables[i]=_lb[i];
}
}
for ( i = 0 ; i < n ; ++i )
{
if ( _input_types[i] == NOMAD::CATEGORICAL )
{
_has_categorical = true;
_all_continuous = false;
break;
}
if ( _input_types[i] != NOMAD::CONTINUOUS )
{
_all_continuous = false;
if ( _has_categorical )
break;
}
}
// variable groups:
reset_var_groups();
std::set::iterator
end = var_groups.end() , it;
bool mod=false;
for ( it = var_groups.begin() ; it != end ; ++it )
{
if ( !(*it)->check ( _fixed_variables , input_types , NULL, mod ) )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): incompatible variable group" );
}
if (mod)
{
std::set tmp_var_groups;
for ( it = var_groups.begin() ; it != end ; ++it )
{
tmp_var_groups.insert(*it);
}
var_groups.clear();
var_groups=tmp_var_groups;
tmp_var_groups.clear();
}
for ( it = var_groups.begin() ; it != end ; ++it )
_var_groups.push_back( new NOMAD::Variable_Group (**it) );
// mesh:
if ( initial_mesh_size.size() != n ||
(min_mesh_size.is_defined() && min_mesh_size.size() != n) ||
(min_poll_size.is_defined() && min_poll_size.size() != n) )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::init(): mesh arguments with different sizes" );
delete _mesh;
try {
_mesh = new NOMAD::Mesh ( initial_mesh_size , min_mesh_size , min_poll_size );
}
catch ( NOMAD::Exception & e )
{
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ ,
*this , e.what() );
}
}
/*--------------------------------------------------*/
/* Access to the number of categorical variables */
/*--------------------------------------------------*/
int NOMAD::Signature::get_n_categorical ( void ) const
{
int n_cat=0;
for (int i = 0 ; i < get_n() ; ++i ) {
if ( _input_types[i] == NOMAD::CATEGORICAL )
n_cat++;
}
return n_cat;
}
/*--------------------------------------------------*/
/* reset */
/*--------------------------------------------------*/
void NOMAD::Signature::reset
( int n ,
const std::vector & input_types ,
const NOMAD::Point & initial_mesh_size ,
const NOMAD::Point & min_mesh_size ,
const NOMAD::Point & min_poll_size ,
const NOMAD::Point & lb ,
const NOMAD::Point & ub ,
const NOMAD::Point & scaling ,
const NOMAD::Point & fixed_variables ,
const std::vector & periodic_variables ,
std::set & var_groups )
{
reset_var_groups();
init ( n ,
input_types ,
initial_mesh_size ,
min_mesh_size ,
min_poll_size ,
lb ,
ub ,
scaling ,
fixed_variables ,
periodic_variables ,
var_groups );
}
/*--------------------------------------------------*/
/* reset_var_groups (private) */
/*--------------------------------------------------*/
void NOMAD::Signature::reset_var_groups ( void )
{
std::list::const_iterator
end = _var_groups.end() , it;
for ( it = _var_groups.begin() ; it != end ; ++it )
delete *it;
_var_groups.clear();
}
/*----------------------------------------------------------*/
/* check the compatibility of a point */
/* . we only check the number of variables */
/* . other stuff (fixed variables, binary variables,...) */
/* will be checked by Eval_Point::check() */
/*----------------------------------------------------------*/
bool NOMAD::Signature::is_compatible ( const NOMAD::Point & x ) const
{
if ( get_n() != x.size() || !_mesh || _var_groups.empty() )
return false;
return true;
}
/*-----------------------------------------------------*/
/* compute the directions (they include delta_m) */
/*-----------------------------------------------------*/
void NOMAD::Signature::get_directions ( std::list & dirs ,
NOMAD::poll_type poll ,
const NOMAD::Point & poll_center ,
int mesh_index )
{
NOMAD::Direction * pd;
int i;
std::list::const_iterator it_dir , end_dir;
std::set::const_iterator it_vi , end_vi;
// get delta_m (mesh size parameter):
int n = get_n();
NOMAD::Point delta_m (n);
NOMAD::Point delta_p (n);
_mesh->get_delta_m ( delta_m , mesh_index );
_mesh->get_delta_p ( delta_p , mesh_index );
// Reset dir_group_index.
// For each signature, a variable_group has a unique set of directions generated and a unique dir_group_index starting by zero (-1 if no dirs)
_dir_group_index=-1;
// loop on variable groups:
std::list::const_iterator end_vg = _var_groups.end() , it_vg;
for ( it_vg = _var_groups.begin() ; it_vg != end_vg ; ++it_vg )
{
const std::set & var_indexes = (*it_vg)->get_var_indexes();
// get the directions for the current group of variables:
std::list dirs_nc;
(*it_vg)->get_directions ( dirs_nc,
poll ,
poll_center ,
mesh_index ,
_feas_success_dir ,
_infeas_success_dir );
// scale with delta_m and resize the directions to size n;
// also round integer and binary variables:
end_dir = dirs_nc.end();
if (static_cast(dirs_nc.size())!=0)
++_dir_group_index;
for ( it_dir = dirs_nc.begin() ; it_dir != end_dir ; ++it_dir )
{
dirs.push_back ( NOMAD::Direction ( n , 0.0 , it_dir->get_type(),_dir_group_index) );
pd = &(*(--dirs.end()));
end_vi = var_indexes.end();
i = 0;
for ( it_vi = var_indexes.begin() ; it_vi != end_vi ; ++it_vi ) {
(*pd)[*it_vi] = delta_m[*it_vi] * (*it_dir)[i++];
// integer variables:
if ( _input_types[*it_vi] == NOMAD::INTEGER )
{
if ( (*pd)[*it_vi] >= delta_p[*it_vi]/3.0 )
(*pd)[*it_vi] = (*pd)[*it_vi].ceil();
else if ( (*pd)[*it_vi] <= -delta_p[*it_vi]/3.0 )
(*pd)[*it_vi] = (*pd)[*it_vi].floor();
else
(*pd)[*it_vi] = (*pd)[*it_vi].round();
}
// binary variables:
else if ( _input_types[*it_vi] == NOMAD::BINARY ) {
if ( (*pd)[*it_vi] != 0.0 )
(*pd)[*it_vi] = 1.0;
}
// categorical variables: set direction=0:
else if ( _input_types[*it_vi] == NOMAD::CATEGORICAL )
(*pd)[*it_vi] = 0.0;
}
}
}
}
/*----------------------------------------------------------------*/
/* get just one direction for a given mesh (used by VNS search) */
/*----------------------------------------------------------------*/
void NOMAD::Signature::get_one_direction ( NOMAD::Direction & dir,
int mesh_index,
int halton_index ) const
{
int i;
std::set::const_iterator it_vi , end_vi;
// get delta_m (mesh size parameter):
int n = get_n();
NOMAD::Point delta_m (n);
_mesh->get_delta_m ( delta_m , mesh_index );
NOMAD::Point delta_p (n);
_mesh->get_delta_p( delta_p , mesh_index );
dir.reset ( n , 0.0 );
dir.set_type ( NOMAD::UNDEFINED_DIRECTION );
// loop on variable groups:
std::list::const_iterator end_vg = _var_groups.end() , it_vg;
for ( it_vg = _var_groups.begin() ; it_vg != end_vg ; ++it_vg ) {
const std::set & var_indexes = (*it_vg)->get_var_indexes();
// get the direction for the current group of variables:
NOMAD::Direction dir_nc;
if ( (*it_vg)->get_one_direction ( dir_nc , mesh_index , halton_index++ ) ) {
// scale with delta_m and round integer and binary variables:
end_vi = var_indexes.end();
i = 0;
for ( it_vi = var_indexes.begin() ; it_vi != end_vi ; ++it_vi ) {
dir[*it_vi] = delta_m[*it_vi] * dir_nc[i++];
// integer variables:
if ( _input_types[*it_vi] == NOMAD::INTEGER ) {
if ( dir[*it_vi] >= delta_p[*it_vi]/3.0 )
dir[*it_vi] = ceil ( dir[*it_vi].value() );
else if ( dir [*it_vi] <= -delta_p[*it_vi]/3.0 )
dir[*it_vi] = floor ( dir[*it_vi].value() );
else
{
double x=dir[*it_vi].value();
dir[*it_vi] = (x>0)? floor(x+0.5): ceil(x-0.5);
}
}
// binary variables:
else if ( _input_types[*it_vi] == NOMAD::BINARY ) {
if ( dir[*it_vi] != 0.0 )
dir[*it_vi] = 1.0;
}
// categorical variables: set direction=0:
else if ( _input_types[*it_vi] == NOMAD::CATEGORICAL )
dir[*it_vi] = 0.0;
}
}
}
}
/*----------------------------------*/
/* scaling */
/* (done before an evaluation) */
/*----------------------------------*/
void NOMAD::Signature::scale ( NOMAD::Point & x )
{
int n = get_n();
if ( n != x.size() )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::scale(x): x.size() != signature.size()" );
NOMAD::Double sci;
for ( int i = 0 ; i < n ; ++i ) {
sci = _scaling[i];
if ( sci.is_defined() )
x[i] *= sci;
}
}
/*----------------------------------*/
/* unscaling */
/* (done after an evaluation) */
/*----------------------------------*/
void NOMAD::Signature::unscale ( NOMAD::Point & x )
{
int n = get_n();
if ( n != x.size() )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::unscale(x): x.size() != signature.size()" );
NOMAD::Double sci;
for ( int i = 0 ; i < n ; ++i ) {
sci = _scaling[i];
if ( sci.is_defined() )
x[i] /= sci;
}
}
/*-----------------------------------------------------------------------*/
/* snap to bounds */
/*-----------------------------------------------------------------------*/
/* . returns true if x has been modified */
/* . supposes that treat_periodic_variables() has already been invoked */
/* (if periodic variables have been treated, then bounds are */
/* satisfied and there is no need to snap anymore */
/*-----------------------------------------------------------------------*/
bool NOMAD::Signature::snap_to_bounds ( NOMAD::Point & x , NOMAD::Direction * direction )
{
int n = get_n();
if ( n != x.size() )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::snap_to_bounds(x): x.size() != signature.size()" );
bool modified = false;
bool no_periodic_var = _periodic_variables.empty();
for ( int i = 0 ; i < n ; ++i )
if ( no_periodic_var || !_periodic_variables[i] ) {
const NOMAD::Double & ubi = _ub[i];
NOMAD::Double & xi = x[i];
if ( ubi.is_defined() && xi > ubi ) {
if (direction)
(*direction)[i] += ubi - xi;
xi = ubi;
modified = true;
}
const NOMAD::Double & lbi = _lb[i];
if ( lbi.is_defined() && xi < lbi ) {
if (direction)
(*direction)[i] += (lbi - xi);
xi = lbi;
modified = true;
}
}
return modified;
}
/*--------------------------------------------------*/
/* treat the periodic variables */
/* returns true if x has been modified */
/*--------------------------------------------------*/
bool NOMAD::Signature::treat_periodic_variables ( NOMAD::Point & x ,
const NOMAD::Direction * old_dir ,
NOMAD::Direction *& new_dir )
{
if ( _periodic_variables.empty() )
return false;
int n = get_n();
if ( n != x.size() )
throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
"NOMAD::Signature::treat_periodic_variables(x): x.size() != signature.size()" );
new_dir = ( old_dir ) ? new NOMAD::Direction (*old_dir) : NULL;
bool modified = false;
for ( int i = 0 ; i < n ; ++i ) {
NOMAD::bb_input_type bbit = _input_types[i];
if ( _periodic_variables[i] && !_fixed_variables[i].is_defined() &&
( bbit == NOMAD::CONTINUOUS || bbit == NOMAD::INTEGER ) ) {
const NOMAD::Double & ubi = _ub[i];
const NOMAD::Double & lbi = _lb[i];
NOMAD::Double & xi = x[i];
bool chk = false;
NOMAD::Double new_x = xi;
while ( new_x > ubi ) {
new_x += lbi - ubi;
chk = true;
}
if ( !chk ) {
while ( new_x < lbi ) {
new_x += ubi - lbi;
chk = true;
}
}
if ( chk ) {
if ( bbit == NOMAD::INTEGER )
new_x.round();
if (new_dir)
(*new_dir)[i] += new_x - xi;
x[i] = new_x;
modified = true;
}
}
}
return modified;
}
/*--------------------------------------------------*/
/* display */
/*--------------------------------------------------*/
void NOMAD::Signature::display ( const NOMAD::Display & out ) const
{
if ( _std )
out << "(standard signature)" << std::endl;
// dimension:
out << "n : " << get_n() << std::endl;
// bounds:
out << "lb : ";
if ( _lb.is_defined() )
out << "( " << _lb << ")";
else
out << "none";
out << std::endl;
out << "ub : ";
if ( _ub.is_defined() )
out << "( " << _ub << ")";
else
out << "none";
out << std::endl;
// scaling:
out << "scaling : ";
if ( _scaling.is_defined() )
out << "( " << _scaling << ")";
else
out << "none";
out << std::endl;
// fixed variables:
out << "fixed variables : ";
if ( _fixed_variables.is_defined() )
out << "( " << _fixed_variables << ")";
else
out << "none";
out << std::endl;
// input types:
out << "input types : (" << _input_types << " )" << std::endl;
// periodic variables:
out << "periodic variables: ";
if ( _periodic_variables.empty() )
out << "none" << std::endl;
else {
size_t pvs = _periodic_variables.size();
out << "{";
for ( size_t k = 0 ; k < pvs ; ++k )
out << _periodic_variables[k] << " ";
out << "}" << std::endl;
}
// success directions:
out << "feas. succ. dir. : ";
if ( _feas_success_dir.is_defined() )
out << _feas_success_dir << std::endl;
else
out << "none";
out << std::endl
<< "infeas. succ. dir.: ";
if ( _infeas_success_dir.is_defined() )
out << _infeas_success_dir;
else
out << "none";
out << std::endl;
// variable groups:
out << NOMAD::open_block ( "variable groups" );
int i = 0;
std::list::const_iterator end = _var_groups.end() , it;
for ( it = _var_groups.begin() ; it != end ; ++it ) {
out << NOMAD::open_block ( "group #" + NOMAD::itos(i++) )
<< **it << NOMAD::close_block();
}
out.close_block();
// mesh:
out << NOMAD::open_block ( "mesh" ) << *_mesh
<< NOMAD::close_block();
}
/*-------------------------------------------*/
/* comparison operator '<' */
/*-------------------------------------------*/
/* (success directions are not considered) */
/*-------------------------------------------*/
bool NOMAD::Signature::operator < ( const NOMAD::Signature & s ) const
{
if ( this == &s )
return false;
// standard signature: not checked: standard and non-standard signatures can be ==
// ( this is tested in Parameters::check() )
// dimension:
// ----------
int n = _lb.size();
int sn = s._lb.size();
if ( n < sn )
return true;
if ( sn < n )
return false;
// variable groups:
// ----------------
int nvg1 = _var_groups.size();
int nvg2 = s._var_groups.size();
if ( nvg1 != nvg2 )
return (nvg1 < nvg2);
std::list::const_iterator
it1 = _var_groups.begin() ,
it2 = s._var_groups.begin() ,
end = _var_groups.end();
while ( it1 != end ) {
if ( **it1 < **it2 )
return true;
if ( **it2 < **it1 )
return false;
++it1;
++it2;
}
// first check on the periodic variables:
// --------------------------------------
bool p1_empty = _periodic_variables.empty();
bool p2_empty = s._periodic_variables.empty();
if ( p1_empty != p2_empty )
return p1_empty;
// first check on the mesh:
// ------------------------
const NOMAD::Point & delta_m_0 = _mesh->get_initial_mesh_size();
const NOMAD::Point & delta_m_min = _mesh->get_min_mesh_size();
const NOMAD::Point & delta_p_min = _mesh->get_min_poll_size();
bool chkm = delta_m_min.is_defined();
bool chkp = delta_p_min.is_defined();
const NOMAD::Point & s_delta_m_0 = s._mesh->get_initial_mesh_size();
const NOMAD::Point & s_delta_m_min = s._mesh->get_min_mesh_size();
const NOMAD::Point & s_delta_p_min = s._mesh->get_min_poll_size();
bool s_chkm = s_delta_m_min.is_defined();
bool s_chkp = s_delta_p_min.is_defined();
if ( _mesh != s._mesh ) {
if ( chkm != s_chkm )
return !chkm;
if ( chkp != s_chkp )
return !chkp;
}
/*---------------------------*/
/* loop on all coordinates */
/*---------------------------*/
for ( int i = 0 ; i < n ; ++i ) {
// input types:
// ------------
if ( _input_types[i] < s._input_types[i] )
return true;
if ( s._input_types[i] < _input_types[i] )
return false;
// bounds:
// -------
if ( _lb[i].comp_with_undef ( s._lb[i] ) )
return true;
if ( s._lb[i].comp_with_undef ( _lb[i] ) )
return false;
if ( _ub[i].comp_with_undef ( s._ub[i] ) )
return true;
if ( s._ub[i].comp_with_undef ( _ub[i] ) )
return false;
// scaling:
// --------
if ( _scaling[i].comp_with_undef ( s._scaling[i] ) )
return true;
if ( s._scaling[i].comp_with_undef ( _scaling[i] ) )
return false;
// fixed variables:
// ----------------
if ( _fixed_variables[i].comp_with_undef ( s._fixed_variables[i] ) )
return true;
if ( s._fixed_variables[i].comp_with_undef ( _fixed_variables[i] ) )
return false;
// periodic variables:
// -------------------
if ( !p1_empty && _periodic_variables[i] != s._periodic_variables[i] )
return _periodic_variables[i];
// mesh:
// -----
if ( _mesh != s._mesh )
{
if ( delta_m_0[i].comp_with_undef ( s_delta_m_0[i] ) )
return true;
if ( s_delta_m_0[i].comp_with_undef ( delta_m_0[i] ) )
return false;
if ( chkm )
{
if ( delta_m_min[i].comp_with_undef ( s_delta_m_min[i] ) )
return true;
if ( s_delta_m_min[i].comp_with_undef ( delta_m_min[i] ) )
return false;
}
if ( chkp )
{
if ( delta_p_min[i].comp_with_undef ( s_delta_p_min[i] ) )
return true;
if ( s_delta_p_min[i].comp_with_undef ( delta_p_min[i] ) )
return false;
}
}
}
// both signatures are equal:
return false;
}