1 /*-------------------------------------------------------------------------------------*/
2 /*  NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2      */
3 /*                                                                                     */
4 /*  Copyright (C) 2001-2015  Mark Abramson        - the Boeing Company, Seattle        */
5 /*                           Charles Audet        - Ecole Polytechnique, Montreal      */
6 /*                           Gilles Couture       - Ecole Polytechnique, Montreal      */
7 /*                           John Dennis          - Rice University, Houston           */
8 /*                           Sebastien Le Digabel - Ecole Polytechnique, Montreal      */
9 /*                           Christophe Tribes    - Ecole Polytechnique, Montreal      */
10 /*                                                                                     */
11 /*  funded in part by AFOSR and Exxon Mobil                                            */
12 /*                                                                                     */
13 /*  Author: Sebastien Le Digabel                                                       */
14 /*                                                                                     */
15 /*  Contact information:                                                               */
16 /*    Ecole Polytechnique de Montreal - GERAD                                          */
17 /*    C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada                  */
18 /*    e-mail: nomad@gerad.ca                                                           */
19 /*    phone : 1-514-340-6053 #6928                                                     */
20 /*    fax   : 1-514-340-5665                                                           */
21 /*                                                                                     */
22 /*  This program is free software: you can redistribute it and/or modify it under the  */
23 /*  terms of the GNU Lesser General Public License as published by the Free Software   */
24 /*  Foundation, either version 3 of the License, or (at your option) any later         */
25 /*  version.                                                                           */
26 /*                                                                                     */
27 /*  This program is distributed in the hope that it will be useful, but WITHOUT ANY    */
28 /*  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A    */
29 /*  PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.   */
30 /*                                                                                     */
31 /*  You should have received a copy of the GNU Lesser General Public License along     */
32 /*  with this program. If not, see <http://www.gnu.org/licenses/>.                     */
33 /*                                                                                     */
34 /*  You can find information on the NOMAD software at www.gerad.ca/nomad               */
35 /*-------------------------------------------------------------------------------------*/
36 /**
37  \file   Signature.cpp
38  \brief  Evaluation point signature (implementation)
39  \author Sebastien Le Digabel
40  \date   2010-04-22
41  \see    Signature.hpp
42  */
43 #include "Signature.hpp"
44 #include "SMesh.hpp"
45 #include "XMesh.hpp"
46 
47 /*-----------------------------------*/
48 /*   static members initialization   */
49 /*-----------------------------------*/
50 #ifdef MEMORY_DEBUG
51 int NOMAD::Signature::_cardinality     = 0;
52 int NOMAD::Signature::_max_cardinality = 0;
53 #endif
54 
55 bool NOMAD::Signature::_warning_has_been_displayed=false;
56 
57 /*--------------------------------------------------*/
58 /*                    constructor 1                 */
59 /*--------------------------------------------------*/
Signature(int n,const std::vector<NOMAD::bb_input_type> & input_types,const NOMAD::Point & lb,const NOMAD::Point & ub,bool use_smesh,bool anisotropic_mesh,const NOMAD::Point & initial_poll_size,const NOMAD::Point & min_poll_size,const NOMAD::Point & min_mesh_size,NOMAD::Double & mesh_update_basis,NOMAD::Double & poll_update_basis,int & mesh_coarsening_exponent,int & mesh_refining_exponent,int initial_mesh_index,const NOMAD::Point & scaling,const NOMAD::Point & fixed_variables,const std::vector<bool> & periodic_variables,std::set<NOMAD::Variable_Group *,NOMAD::VG_Comp> & var_groups,const NOMAD::Display & out)60 NOMAD::Signature::Signature
61 ( int												n					,
62  const std::vector<NOMAD::bb_input_type>			& input_types		,
63  const NOMAD::Point									& lb				,
64  const NOMAD::Point									& ub				,
65  bool                                               use_smesh           ,
66  bool												anisotropic_mesh	,
67  const NOMAD::Point									& initial_poll_size	,
68  const NOMAD::Point									& min_poll_size		,
69  const NOMAD::Point									& min_mesh_size		,
70  NOMAD::Double										& mesh_update_basis	,
71  NOMAD::Double										& poll_update_basis	,
72  int												& mesh_coarsening_exponent,
73  int												& mesh_refining_exponent,
74  int												initial_mesh_index	,
75  const NOMAD::Point									& scaling			,
76  const NOMAD::Point									& fixed_variables   ,
77  const std::vector<bool>							& periodic_variables,
78  std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>	& var_groups        ,
79  const NOMAD::Display								& out )
80 :  _std  ( false ) ,
81 _out ( out )
82 {
83     // Mesh index starts at 0 for an xmesh and decreases as the mesh size decreases
84     // The mesh index is reset to 0 as the mesh is reset.
85     if ( ! use_smesh )
86         _mesh=new NOMAD::XMesh(anisotropic_mesh,
87                                initial_poll_size,
88                                min_poll_size,
89                                min_mesh_size,
90                                fixed_variables,
91                                poll_update_basis,  // XMesh set poll update basis (default 2)
92                                mesh_coarsening_exponent,
93                                mesh_refining_exponent);
94     else   // Mesh index can be provided for isotropic smesh and increases as the mesh size decreases
95         _mesh=new NOMAD::SMesh(initial_poll_size,   // new initial_poll_size ~ old initial mesh size
96                                min_poll_size,
97                                min_mesh_size,
98                                fixed_variables,
99                                mesh_update_basis, // SMesh set mesh update basis (default 4)
100                                mesh_coarsening_exponent,
101                                mesh_refining_exponent,
102                                initial_mesh_index );
103 
104     init ( n              ,
105           input_types        ,
106           lb                 ,
107           ub                 ,
108           scaling            ,
109           fixed_variables    ,
110           periodic_variables ,
111           var_groups           );
112 
113 #ifdef MEMORY_DEBUG
114     ++NOMAD::Signature::_cardinality;
115     if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality )
116         ++NOMAD::Signature::_max_cardinality;
117 #endif
118 }
119 
120 /*--------------------------------------------------*/
121 /*                    constructor 2                 */
122 /*--------------------------------------------------*/
Signature(int n,const std::vector<NOMAD::bb_input_type> & input_types,const NOMAD::Point & initial_poll_size,const NOMAD::Point & lb,const NOMAD::Point & ub,const std::set<NOMAD::direction_type> & direction_types,const std::set<NOMAD::direction_type> & sec_poll_dir_types,const NOMAD::Display & out)123 NOMAD::Signature::Signature
124 ( int                                       n                  ,
125  const std::vector<NOMAD::bb_input_type> & input_types        ,
126  const NOMAD::Point						& initial_poll_size	,
127  const NOMAD::Point                      & lb                 ,
128  const NOMAD::Point                      & ub                 ,
129  const std::set<NOMAD::direction_type>   & direction_types    ,
130  const std::set<NOMAD::direction_type>   & sec_poll_dir_types ,
131  const NOMAD::Display                    & out                  )
132 :	_std  ( false ) ,
133 _out  ( out )
134 {
135     if ( static_cast<int> ( input_types.size() ) != n )
136         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
137                                                  "NOMAD::Signature::Signature(): bad argument: input_types" );
138 
139     // Default mesh is isotropic xmesh
140     //------------------------------------------
141     _mesh=new NOMAD::XMesh (false,
142                             initial_poll_size,
143                             NOMAD::Point(),
144                             NOMAD::Point(),
145                             NOMAD::Point());
146 
147 
148     // automatic creation of groups of variables:
149     // ------------------------------------------
150     std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> var_groups;
151 
152     {
153         std::set<int> vi_cbi;  // list of cont./bin./int. variables
154         std::set<int> vi_cat;  // list of categorical variables
155 
156         for ( int i = 0 ; i < n ; ++i )
157             if (  input_types[i] != NOMAD::CATEGORICAL )
158                 vi_cbi.insert(i);
159             else
160                 vi_cat.insert(i);
161 
162         // creation of a group for cont./bin./int. variables:
163         if ( !vi_cbi.empty() )
164             var_groups.insert ( new NOMAD::Variable_Group ( vi_cbi             ,
165                                                            direction_types    ,
166                                                            sec_poll_dir_types ,
167                                                            out                  ) );
168 
169         // creation of a group for categorical variables:
170         if ( !vi_cat.empty() )
171             var_groups.insert ( new NOMAD::Variable_Group ( vi_cat            ,
172                                                            direction_types   ,
173                                                            sec_poll_dir_types,
174                                                            out                 ) );
175 
176     }
177 
178     // init:
179     // -----
180     init ( n                   ,
181           input_types         ,
182           lb                  ,
183           ub                  ,
184           NOMAD::Point()      ,
185           NOMAD::Point()      ,
186           std::vector<bool>() ,
187           var_groups            );
188 
189     // delete the temporary groups of variables:
190     std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::iterator
191     it , end = var_groups.end();
192 
193     for ( it = var_groups.begin() ; it != end ; ++it )
194         delete *it;
195 
196 #ifdef MEMORY_DEBUG
197     ++NOMAD::Signature::_cardinality;
198     if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality )
199         ++NOMAD::Signature::_max_cardinality;
200 #endif
201 }
202 
203 /*--------------------------------------------------*/
204 /*                  copy constructor                */
205 /*--------------------------------------------------*/
Signature(const NOMAD::Signature & s)206 NOMAD::Signature::Signature ( const NOMAD::Signature & s )
207 :  _lb                 ( s._lb                     ) ,
208 _ub                 ( s._ub                     ) ,
209 _scaling            ( s._scaling                ) ,
210 _fixed_variables    ( s._fixed_variables        ) ,
211 _input_types        ( s._input_types            ) ,
212 _all_continuous     ( s._all_continuous         ) ,
213 _has_categorical    ( s._has_categorical		 ) ,
214 _periodic_variables ( s._periodic_variables	 ) ,
215 _std                ( false                     ) ,
216 _feas_success_dir   ( s._feas_success_dir       ) ,
217 _infeas_success_dir ( s._infeas_success_dir     ) ,
218 _out (s._out)
219 {
220 
221 
222     if (dynamic_cast<NOMAD::SMesh*> (s._mesh))
223         _mesh = new NOMAD::SMesh (*(static_cast<NOMAD::SMesh*>(s._mesh)));
224     else
225         _mesh = new NOMAD::XMesh (*(static_cast<NOMAD::XMesh*>(s._mesh)));
226 
227     std::list<NOMAD::Variable_Group *>::const_iterator it , end = s._var_groups.end();
228     for ( it = s._var_groups.begin() ; it != end ; ++it )
229         _var_groups.push_back ( new NOMAD::Variable_Group(**it) );
230 
231 #ifdef MEMORY_DEBUG
232     ++NOMAD::Signature::_cardinality;
233     if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality )
234         ++NOMAD::Signature::_max_cardinality;
235 #endif
236 }
237 
238 /*--------------------------------------------------*/
239 /*                    destructor                    */
240 /*--------------------------------------------------*/
~Signature(void)241 NOMAD::Signature::~Signature ( void )
242 {
243     clear();
244 #ifdef MEMORY_DEBUG
245     --NOMAD::Signature::_cardinality;
246 #endif
247 }
248 
249 /*--------------------------------------------------------------------------------*/
250 /*  clear (private method called by destructor and after an exception is thrown)  */
251 /*--------------------------------------------------------------------------------*/
clear(void)252 void NOMAD::Signature::clear ( void )
253 {
254     _all_continuous  = true;
255     _has_categorical = false;
256     _std             = false;
257     reset_var_groups();
258     _feas_success_dir.clear();
259     _infeas_success_dir.clear();
260     _lb.clear();
261     _ub.clear();
262     _scaling.clear();
263     _fixed_variables.clear();
264     _input_types.clear();
265     _periodic_variables.clear();
266     delete _mesh;
267 
268 }
269 
270 /*--------------------------------------------------*/
271 /*            feasible success direction            */
272 /*--------------------------------------------------*/
set_feas_success_dir(const NOMAD::Direction & d)273 void NOMAD::Signature::set_feas_success_dir ( const NOMAD::Direction & d )
274 {
275     if ( d.size() != static_cast<int>(_input_types.size()) )
276         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
277                                                  "NOMAD::Signature::set_feas_success_dir(): bad direction" );
278     _feas_success_dir = d;
279 }
280 
281 /*--------------------------------------------------*/
282 /*            infeasible success direction          */
283 /*--------------------------------------------------*/
set_infeas_success_dir(const NOMAD::Direction & d)284 void NOMAD::Signature::set_infeas_success_dir ( const NOMAD::Direction & d )
285 {
286     if ( d.size() != static_cast<int>(_input_types.size()) )
287         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
288                                                  "NOMAD::Signature::set_infeas_success_dir(): bad direction" );
289     _infeas_success_dir = d;
290 }
291 
292 
293 /*--------------------------------------------------*/
294 /*               initializations (private)          */
295 /*--------------------------------------------------*/
init(int n,const std::vector<NOMAD::bb_input_type> & input_types,const NOMAD::Point & lb,const NOMAD::Point & ub,const NOMAD::Point & scaling,const NOMAD::Point & fixed_variables,const std::vector<bool> & periodic_variables,std::set<NOMAD::Variable_Group *,NOMAD::VG_Comp> & var_groups)296 void NOMAD::Signature::init
297 ( int                                       n                  ,
298  const std::vector<NOMAD::bb_input_type> & input_types        ,
299  const NOMAD::Point                      & lb                 ,
300  const NOMAD::Point                      & ub                 ,
301  const NOMAD::Point                      & scaling            ,
302  const NOMAD::Point                      & fixed_variables    ,
303  const std::vector<bool>                 & periodic_variables ,
304  std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups )
305 {
306     // reset directions:
307     _feas_success_dir.clear();
308     _infeas_success_dir.clear();
309 
310     // check the dimension (n):
311     if ( n <= 0 )
312         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
313                                                  "NOMAD::Signature::init(): bad argument: n" );
314 
315     // bounds:
316     if ( lb.empty() )
317         _lb.reset ( n );
318     else if ( lb.size() == n )
319         _lb = lb;
320     else
321         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
322                                                  "NOMAD::Signature::init(): bad argument: lb" );
323     if ( ub.empty() )
324         _ub.reset ( n );
325     else if ( ub.size() == n )
326         _ub = ub;
327     else
328         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
329                                                  "NOMAD::Signature::init(): bad argument: ub" );
330 
331     // scaling:
332     if ( scaling.empty() )
333         _scaling.reset ( n );
334     else if ( scaling.size() == n )
335         _scaling = scaling;
336     else
337         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
338                                                  "NOMAD::Signature::init(): bad argument: scaling" );
339     int i;
340     for ( i = 0 ; i < n ; ++i )
341         if ( _scaling[i].is_defined() && _scaling[i] == 0.0 )
342             throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
343                                                      "NOMAD::Signature::init(): bad argument: scaling (zero value)" );
344 
345     // fixed variables:
346     if ( fixed_variables.empty() )
347         _fixed_variables.reset ( n );
348     else if ( fixed_variables.size() == n )
349         _fixed_variables = fixed_variables;
350     else
351         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
352                                                  "NOMAD::Signature::init(): bad argument: fixed_variables" );
353 
354     // periodic variables:
355     _periodic_variables = periodic_variables;
356     if ( !_periodic_variables.empty() )
357     {
358 
359         if ( static_cast<int>(periodic_variables.size()) != n )
360             throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
361                                                      "NOMAD::Signature::init(): bad argument: periodic_variables" );
362 
363         for ( i = 0 ; i < n ; ++i )
364             if ( _periodic_variables[i] && ( !_lb[i].is_defined() || !_ub[i].is_defined() ) )
365                 throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
366                                                          "NOMAD::Signature::init(): incompatible periodic variables" );
367     }
368 
369     // input types:
370     if ( static_cast<int>(input_types.size()) != n )
371         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
372                                                  "NOMAD::Signature::init(): bad argument: input_types" );
373     _input_types     = input_types;
374     _all_continuous  = true;
375     _has_categorical = false;
376 
377     for ( i = 0 ; i < n ; ++i )
378     {
379 
380         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  )
381         {
382             _out << NOMAD::open_block("Warning:")
383             << "NOMAD::Signature::init(): Providing explicit bounds for categorical variables is irrelevant. Bounds are provided implicitely by the neighbors function." << std::endl
384             << NOMAD::close_block();
385             _warning_has_been_displayed=true;
386         }
387 
388         if ( _fixed_variables[i].is_defined() && ((_lb[i].is_defined() && _fixed_variables[i] < _lb[i]) || (_ub[i].is_defined() && _fixed_variables[i] > _ub[i]) ||
389                                                   ( (_input_types[i] == NOMAD::INTEGER     ||   _input_types[i] == NOMAD::CATEGORICAL    )
390                                                    && !_fixed_variables[i].is_integer() )  ||
391                                                   ( _input_types[i] == NOMAD::BINARY && !_fixed_variables[i].is_binary() ) ) )
392             throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
393                                                      "NOMAD::Signature::init(): bad argument: fixed variable inconsistent with bounds or input types" );
394 
395         if ( _lb[i].is_defined() && _ub[i].is_defined() )
396         {
397             if ( _lb[i].is_defined() && _ub[i].is_defined() && _lb[i].value()> ub[i].value() )
398             {
399                 throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
400                                                          "NOMAD::Signature::init(): bad argument: lower bound must be lower than upper bound!" );
401             }
402             if ( _lb[i] == _ub[i] )
403                 _fixed_variables[i]=_lb[i];
404         }
405     }
406     for ( i = 0 ; i < n ; ++i )
407     {
408         if ( _input_types[i] == NOMAD::CATEGORICAL )
409         {
410             _has_categorical = true;
411             _all_continuous  = false;
412             break;
413         }
414         if ( _input_types[i] != NOMAD::CONTINUOUS )
415         {
416             _all_continuous = false;
417             if ( _has_categorical )
418                 break;
419         }
420 
421 
422     }
423 
424     // variable groups:
425     reset_var_groups();
426 
427     std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::iterator
428     end = var_groups.end() , it;
429     bool mod=false;
430     for ( it = var_groups.begin() ; it != end ; ++it )
431     {
432 
433 
434         if ( !(*it)->check ( _fixed_variables , input_types , NULL, mod ) )
435             throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
436                                                      "NOMAD::Signature::init(): incompatible variable group" );
437 
438     }
439 
440     // if the indices in var_groups have been modified than var_groups is reconstructed to ensure proper ordering
441     if ( mod )
442     {
443         std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> tmp_var_groups;
444         for ( it = var_groups.begin() ; it != end ; ++it )
445         {
446             tmp_var_groups.insert(*it);
447         }
448         var_groups.clear();
449         var_groups=tmp_var_groups;
450         tmp_var_groups.clear();
451 
452     }
453 
454     for ( it = var_groups.begin() ; it != end ; ++it )
455         _var_groups.push_back( new NOMAD::Variable_Group (**it) );
456 
457     // mesh:
458     if ( _mesh->get_initial_poll_size().size() != n                             ||
459         ( _mesh->get_min_mesh_size().is_defined() && _mesh->get_min_mesh_size().size() != n) ||
460         ( _mesh->get_min_poll_size().is_defined() && _mesh->get_min_poll_size().size() != n)    )
461         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
462                                                  "NOMAD::Signature::init(): mesh arguments with different sizes" );
463 
464 
465 
466 }
467 
468 /*--------------------------------------------------*/
469 /* Access to the number of categorical variables */
470 /*--------------------------------------------------*/
get_n_categorical(void) const471 int NOMAD::Signature::get_n_categorical ( void ) const
472 {
473     int n_cat=0;
474     for (int i = 0 ; i < get_n() ; ++i )
475         if ( _input_types[i] == NOMAD::CATEGORICAL )
476             n_cat++;
477 
478     return n_cat;
479 }
480 
481 /*--------------------------------------------------*/
482 /* Access to the number of categorical variables */
483 /*--------------------------------------------------*/
get_nb_fixed_variables(void) const484 int NOMAD::Signature::get_nb_fixed_variables ( void ) const
485 {
486     int n_fixed=0;
487     for (int i = 0 ; i < get_n() ; ++i )
488         if ( _fixed_variables[i].is_defined() )
489             n_fixed++;
490 
491     return n_fixed;
492 }
493 
494 
495 
496 /*--------------------------------------------------*/
497 /*                       reset                      */
498 /*--------------------------------------------------*/
reset(int n,const std::vector<NOMAD::bb_input_type> & input_types,const NOMAD::Point & lb,const NOMAD::Point & ub,const NOMAD::Point & scaling,const NOMAD::Point & fixed_variables,const std::vector<bool> & periodic_variables,std::set<NOMAD::Variable_Group *,NOMAD::VG_Comp> & var_groups)499 void NOMAD::Signature::reset
500 ( int                                       n                        ,
501  const std::vector<NOMAD::bb_input_type> & input_types              ,
502  const NOMAD::Point                      & lb                       ,
503  const NOMAD::Point                      & ub                       ,
504  const NOMAD::Point                      & scaling                  ,
505  const NOMAD::Point                      & fixed_variables          ,
506  const std::vector<bool>                 & periodic_variables       ,
507  std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups   )
508 {
509     reset_mesh();
510     reset_var_groups();
511     init ( n                  ,
512           input_types        ,
513           lb                 ,
514           ub                 ,
515           scaling            ,
516           fixed_variables    ,
517           periodic_variables ,
518           var_groups           );
519 }
520 
521 /*--------------------------------------------------*/
522 /*                reset_var_groups (private)        */
523 /*--------------------------------------------------*/
reset_var_groups(void)524 void NOMAD::Signature::reset_var_groups ( void )
525 {
526     std::list<NOMAD::Variable_Group *>::const_iterator
527     end = _var_groups.end() , it;
528     for ( it = _var_groups.begin() ; it != end ; ++it )
529         delete *it;
530     _var_groups.clear();
531 }
532 
533 /*----------------------------------------------------------*/
534 /*           check the compatibility of a point             */
535 /*   . we only check the number of variables                */
536 /*   . other stuff (fixed variables, binary variables,...)  */
537 /*     will be checked by Eval_Point::check()               */
538 /*----------------------------------------------------------*/
is_compatible(const NOMAD::Point & x) const539 bool NOMAD::Signature::is_compatible ( const NOMAD::Point & x ) const
540 {
541     if ( get_n() != x.size() || _var_groups.empty() )
542         return false;
543     return true;
544 }
545 
546 /*-----------------------------------------------------*/
547 /*     compute the directions                          */
548 /*-----------------------------------------------------*/
get_directions(std::list<NOMAD::Direction> & dirs,NOMAD::poll_type poll,const NOMAD::Point & poll_center)549 void NOMAD::Signature::get_directions ( std::list<NOMAD::Direction>	& dirs			,
550                                        NOMAD::poll_type				poll			,
551                                        const NOMAD::Point			& poll_center   )
552 {
553 
554     NOMAD::Direction                          * pd;
555     int                                         i;
556     std::list<NOMAD::Direction>::const_iterator it_dir , end_dir;
557     std::set<int>::const_iterator               it_vi  , end_vi;
558 
559     int          n = get_n();
560     NOMAD::Point delta=_mesh->get_delta ( );
561     NOMAD::Point Delta=_mesh->get_Delta ( );
562 
563 
564     // Reset dir_group_index.
565     //	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)
566     _dir_group_index=-1;
567 
568     // loop on variable groups:
569     std::list<NOMAD::Variable_Group*>::const_iterator end_vg = _var_groups.end() , it_vg;
570     for ( it_vg = _var_groups.begin() ; it_vg != end_vg ; ++it_vg )
571     {
572 
573         const std::set<int> & var_indexes = (*it_vg)->get_var_indexes();
574 
575         // get the directions on a unit nc-sphere for the current group of variables:
576         std::list<NOMAD::Direction> dirs_nc;
577         (*it_vg)->get_directions ( dirs_nc , poll , *_mesh );  // _mesh of all directions
578 
579 
580         // scale with delta and resize the directions to size n;
581         // also round integer and binary variables:
582         end_dir = dirs_nc.end();
583         if (static_cast<int>(dirs_nc.size())!=0)
584             ++_dir_group_index;
585         for ( it_dir = dirs_nc.begin() ; it_dir != end_dir ; ++it_dir )
586         {
587 
588             dirs.push_back ( NOMAD::Direction ( n , 0.0 , it_dir->get_type(),_dir_group_index) );
589 
590             pd = &(*(--dirs.end()));
591 
592             end_vi = var_indexes.end();
593             i      = 0;
594 
595 
596             for ( it_vi = var_indexes.begin() ; it_vi != end_vi ; ++it_vi ,++i)
597             {
598                 // Scaling and projection on the mesh
599                 (*pd)[*it_vi] = _mesh->scale_and_project(*it_vi,(*it_dir)[i]);
600 
601                 // integer variables:
602                 if ( _input_types[*it_vi] == NOMAD::INTEGER )
603                 {
604                     if ( (*pd)[*it_vi] >= Delta[*it_vi]/3.0 )
605                         (*pd)[*it_vi] =  (*pd)[*it_vi].ceil();
606                     else if ( (*pd)[*it_vi] <= -Delta[*it_vi]/3.0 )
607                         (*pd)[*it_vi] =  (*pd)[*it_vi].floor();
608                     else
609                         (*pd)[*it_vi] =  (*pd)[*it_vi].round();
610                 }
611 
612                 // binary variables:
613                 else if ( _input_types[*it_vi] == NOMAD::BINARY )
614                 {
615                     if ( (*pd)[*it_vi] != 0.0 )
616                         (*pd)[*it_vi] = 1.0;
617                 }
618 
619                 // categorical variables: set direction=0:
620                 else if ( _input_types[*it_vi] == NOMAD::CATEGORICAL )
621                     (*pd)[*it_vi] = 0.0;
622             }
623 
624         }
625     }
626 }
627 
628 /*----------------------------------------------------------------*/
629 /*  get just one direction for a given mesh (used by VNS search)  */
630 /*----------------------------------------------------------------*/
get_one_direction(NOMAD::Direction & dir,int ell) const631 void NOMAD::Signature::get_one_direction ( NOMAD::Direction & dir , int ell) const
632 {
633     int                           i;
634     std::set<int>::const_iterator it_vi  , end_vi;
635 
636     // get delta_m (mesh size parameter):
637     int          n = get_n();
638     NOMAD::Point delta=_mesh->get_delta ( );
639     NOMAD::Point Delta=_mesh->get_Delta ( );
640 
641     dir.reset    ( n , 0.0 );
642     dir.set_type ( NOMAD::UNDEFINED_DIRECTION );
643 
644     // The mesh indices are modified and must be reset properly once the one direction is obtained
645     const NOMAD::Point old_mesh_indices=_mesh->get_mesh_indices();
646     NOMAD::Point modified_mesh_indices(n,NOMAD::Double(ell));
647     _mesh->set_mesh_indices(modified_mesh_indices);
648 
649     // loop on variable groups:
650     std::list<NOMAD::Variable_Group*>::const_iterator end_vg = _var_groups.end() , it_vg;
651     for ( it_vg = _var_groups.begin() ; it_vg != end_vg ; ++it_vg )
652     {
653 
654         const std::set<int> & var_indexes = (*it_vg)->get_var_indexes();
655 
656         // get the direction for the current group of variables:
657         NOMAD::Direction dir_nc ( static_cast<int>(var_indexes.size()) , 0.0 , NOMAD::UNDEFINED_DIRECTION );
658 
659         // get a direction on a unit nc-sphere
660         if ( (*it_vg)->get_one_direction ( dir_nc ) )
661         {
662 
663             // scale with delta_m and round integer and binary variables:
664             end_vi = var_indexes.end();
665             i      = 0;
666             for ( it_vi = var_indexes.begin() ; it_vi != end_vi ; ++it_vi )
667             {
668 
669                 dir[*it_vi]=_mesh->scale_and_project(*it_vi,dir_nc[i++]);
670 
671 
672                 // integer variables:
673                 if ( _input_types[*it_vi] == NOMAD::INTEGER )
674                 {
675                     if ( dir[*it_vi] >= Delta[*it_vi]/3.0 )
676                         dir[*it_vi] = ceil  ( dir[*it_vi].value() );
677                     else if ( dir [*it_vi] <= -Delta[*it_vi]/3.0 )
678                         dir[*it_vi] = floor ( dir[*it_vi].value() );
679                     else
680                     {
681                         double x=dir[*it_vi].value();
682                         dir[*it_vi] = (x>0)? floor(x+0.5): ceil(x-0.5);
683                     }
684                 }
685 
686                 // binary variables:
687                 else if ( _input_types[*it_vi] == NOMAD::BINARY )
688                 {
689                     if ( dir[*it_vi] != 0.0 )
690                         dir[*it_vi] = 1.0;
691                 }
692 
693                 // categorical variables: set direction=0:
694                 else if ( _input_types[*it_vi] == NOMAD::CATEGORICAL )
695                     dir[*it_vi] = 0.0;
696             }
697         }
698     }
699 
700     // Reset the mesh indices to their previous values
701     _mesh->set_mesh_indices(old_mesh_indices);
702 }
703 
704 /*----------------------------------*/
705 /*             scaling              */
706 /*    (done before an evaluation)   */
707 /*----------------------------------*/
scale(NOMAD::Point & x)708 void NOMAD::Signature::scale ( NOMAD::Point & x )
709 {
710     int n = get_n();
711     if ( n != x.size() )
712         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
713                                                  "NOMAD::Signature::scale(x): x.size() != signature.size()" );
714     NOMAD::Double sci;
715     for ( int i = 0 ; i < n ; ++i )
716     {
717         sci = _scaling[i];
718         if ( sci.is_defined() )
719             x[i] *= sci;
720     }
721 }
722 
723 /*----------------------------------*/
724 /*             unscaling            */
725 /*    (done after an evaluation)    */
726 /*----------------------------------*/
unscale(NOMAD::Point & x)727 void NOMAD::Signature::unscale ( NOMAD::Point & x )
728 {
729     int n = get_n();
730     if ( n != x.size() )
731         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
732                                                  "NOMAD::Signature::unscale(x): x.size() != signature.size()" );
733     NOMAD::Double sci;
734     for ( int i = 0 ; i < n ; ++i )
735     {
736         sci = _scaling[i];
737         if ( sci.is_defined() )
738             x[i] /= sci;
739     }
740 }
741 
742 /*-----------------------------------------------------------------------*/
743 /*                             snap to bounds                            */
744 /*-----------------------------------------------------------------------*/
745 /*  . returns true if x has been modified                                */
746 /*  . supposes that treat_periodic_variables() has already been invoked  */
747 /*    (if periodic variables have been treated, then bounds are          */
748 /*     satisfied and there is no need to snap anymore                    */
749 /*-----------------------------------------------------------------------*/
snap_to_bounds(NOMAD::Point & x,NOMAD::Direction * direction)750 bool NOMAD::Signature::snap_to_bounds ( NOMAD::Point & x , NOMAD::Direction * direction )
751 {
752     int n = get_n();
753     if ( n != x.size() )
754         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
755                                                  "NOMAD::Signature::snap_to_bounds(x): x.size() != signature.size()" );
756 
757     bool modified        = false;
758     bool no_periodic_var = _periodic_variables.empty();
759 
760     for ( int i = 0 ; i < n ; ++i )
761 
762         if ( no_periodic_var || !_periodic_variables[i] )
763         {
764 
765             const NOMAD::Double & ubi = _ub[i];
766             NOMAD::Double       & xi  = x[i];
767             if ( ubi.is_defined() && xi > ubi )
768             {
769                 if (direction)
770                     (*direction)[i] += ubi - xi;
771                 xi       = ubi;
772                 modified = true;
773             }
774             const NOMAD::Double & lbi = _lb[i];
775             if ( lbi.is_defined() && xi < lbi )
776             {
777                 if (direction)
778                     (*direction)[i] += (lbi - xi);
779                 xi       = lbi;
780                 modified = true;
781             }
782         }
783 
784     return modified;
785 }
786 
787 /*--------------------------------------------------*/
788 /*             treat the periodic variables         */
789 /*         returns true if x has been modified      */
790 /*--------------------------------------------------*/
treat_periodic_variables(NOMAD::Point & x,const NOMAD::Direction * old_dir,NOMAD::Direction * & new_dir)791 bool NOMAD::Signature::treat_periodic_variables ( NOMAD::Point            & x       ,
792                                                  const NOMAD::Direction *  old_dir ,
793                                                  NOMAD::Direction       *& new_dir   )
794 {
795     if ( _periodic_variables.empty() )
796         return false;
797 
798     int n = get_n();
799     if ( n != x.size() )
800         throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this ,
801                                                  "NOMAD::Signature::treat_periodic_variables(x): x.size() != signature.size()" );
802 
803     new_dir = ( old_dir ) ? new NOMAD::Direction (*old_dir) : NULL;
804 
805     bool modified = false;
806 
807     for ( int i = 0 ; i < n ; ++i )
808     {
809 
810         NOMAD::bb_input_type bbit = _input_types[i];
811 
812 
813         if ( _periodic_variables[i] && !_fixed_variables[i].is_defined() &&
814             ( bbit == NOMAD::CONTINUOUS || bbit == NOMAD::INTEGER ) )
815         {
816 
817             const NOMAD::Double & ubi = _ub[i];
818             const NOMAD::Double & lbi = _lb[i];
819             NOMAD::Double       & xi  = x[i];
820 
821             bool chk = false;
822 
823             NOMAD::Double new_x = xi;
824             while ( new_x > ubi )
825             {
826                 new_x += lbi - ubi;
827                 chk    = true;
828             }
829 
830             if ( !chk )
831             {
832                 while ( new_x < lbi )
833                 {
834                     new_x += ubi - lbi;
835                     chk    = true;
836                 }
837             }
838 
839             if ( chk )
840             {
841 
842                 if ( bbit == NOMAD::INTEGER )
843                     new_x.round();
844 
845                 if (new_dir)
846                     (*new_dir)[i] += new_x - xi;
847 
848                 x[i]     = new_x;
849                 modified = true;
850             }
851         }
852     }
853 
854     return modified;
855 }
856 
857 /*--------------------------------------------------*/
858 /*                      display                     */
859 /*--------------------------------------------------*/
display(const NOMAD::Display & out) const860 void NOMAD::Signature::display ( const NOMAD::Display & out ) const
861 {
862     if ( _std )
863         out << "(standard signature)" << std::endl;
864 
865     // dimension:
866     out << "n                 : "  << get_n() << std::endl;
867 
868     // bounds:
869     out << "lb                : ";
870     if ( _lb.is_defined() )
871         out << "( " << _lb << ")";
872     else
873         out << "none";
874     out << std::endl;
875     out << "ub                : ";
876     if ( _ub.is_defined() )
877         out << "( " << _ub << ")";
878     else
879         out << "none";
880     out << std::endl;
881 
882     // scaling:
883     out << "scaling           : ";
884     if ( _scaling.is_defined() )
885         out << "( " << _scaling << ")";
886     else
887         out << "none";
888     out << std::endl;
889 
890     // fixed variables:
891     out << "fixed variables   : ";
892     if ( _fixed_variables.is_defined() )
893         out << "( " << _fixed_variables << ")";
894     else
895         out << "none";
896     out << std::endl;
897 
898     // input types:
899     out << "input types       : (" << _input_types << " )" << std::endl;
900 
901     // periodic variables:
902     out << "periodic variables: ";
903     if ( _periodic_variables.empty() )
904         out << "none" << std::endl;
905     else
906     {
907         size_t pvs = _periodic_variables.size();
908         out << "{";
909         for ( size_t k = 0 ; k < pvs ; ++k )
910             out << _periodic_variables[k] << " ";
911         out << "}" << std::endl;
912     }
913 
914     // success directions:
915     out << "feas. succ. dir.  : ";
916     if ( _feas_success_dir.is_defined() )
917         out << _feas_success_dir << std::endl;
918     else
919         out << "none";
920     out << std::endl
921     << "infeas. succ. dir.: ";
922     if ( _infeas_success_dir.is_defined() )
923         out << _infeas_success_dir;
924     else
925         out << "none";
926     out << std::endl;
927 
928     // variable groups:
929     out << NOMAD::open_block ( "variable groups" );
930     int i = 0;
931     std::list<NOMAD::Variable_Group *>::const_iterator end = _var_groups.end() , it;
932     for ( it = _var_groups.begin() ; it != end ; ++it )
933     {
934         out << NOMAD::open_block ( "group #" + NOMAD::itos(i++) )
935         << **it << NOMAD::close_block();
936     }
937     out.close_block();
938 
939     // mesh:
940     out << NOMAD::open_block ( "mesh" ) ;
941     out << "initial poll size: ( " << _mesh->get_initial_poll_size() << " )" << std::endl;
942     out << "initial mesh size: ( " << _mesh->get_initial_mesh_size() << " )" << std::endl;
943     out << "minimum mesh size: ( " << _mesh->get_min_mesh_size() << " )" << std::endl;
944     out << "minimum poll size: ( " << _mesh->get_min_poll_size() << " )" << std::endl;
945     out << NOMAD::close_block();
946 }
947 
948 /*-------------------------------------------*/
949 /*           comparison operator '<'         */
950 /*-------------------------------------------*/
951 /*  (success directions are not considered)  */
952 /*-------------------------------------------*/
operator <(const NOMAD::Signature & s) const953 bool NOMAD::Signature::operator < ( const NOMAD::Signature & s ) const
954 {
955     if ( this == &s )
956         return false;
957 
958     // standard signature: not checked: standard and non-standard signatures can be ==
959     // ( this is tested in Parameters::check() )
960 
961     // dimension:
962     // ----------
963     int  n = static_cast<int>(_lb.size());
964     int sn = static_cast<int>(s._lb.size());
965 
966     if ( n < sn )
967         return true;
968     if ( sn < n )
969         return false;
970 
971     // variable groups:
972     // ----------------
973     size_t nvg1 = _var_groups.size();
974     size_t nvg2 = s._var_groups.size();
975     if ( nvg1 != nvg2 )
976         return (nvg1 < nvg2);
977 
978     std::list<NOMAD::Variable_Group*>::const_iterator
979     it1 =   _var_groups.begin() ,
980     it2 = s._var_groups.begin() ,
981     end =   _var_groups.end();
982 
983     while ( it1 != end )
984     {
985         if ( **it1 < **it2 )
986             return true;
987         if ( **it2 < **it1 )
988             return false;
989         ++it1;
990         ++it2;
991     }
992 
993     // first check on the periodic variables:
994     // --------------------------------------
995     bool p1_empty = _periodic_variables.empty();
996     bool p2_empty = s._periodic_variables.empty();
997     if ( p1_empty != p2_empty )
998         return p1_empty;
999 
1000     // first check on the mesh:
1001     // ------------------------
1002     bool                 chkm          = _mesh->get_min_mesh_size().is_defined();
1003     bool                 chkp          = _mesh->get_min_poll_size().is_defined();
1004 
1005     bool                 s_chkm        = s._mesh->get_min_mesh_size().is_defined();
1006     bool                 s_chkp        = s._mesh->get_min_poll_size().is_defined();
1007 
1008     if ( _mesh->get_initial_mesh_size() != s._mesh->get_initial_mesh_size() &&
1009         _mesh->get_min_mesh_size() != s._mesh->get_min_mesh_size() &&
1010         _mesh->get_min_poll_size() != s._mesh->get_min_poll_size() )
1011     {
1012         if ( chkm != s_chkm )
1013             return !chkm;
1014         if ( chkp != s_chkp )
1015             return !chkp;
1016     }
1017 
1018     /*---------------------------*/
1019     /*  loop on all coordinates  */
1020     /*---------------------------*/
1021     for ( int i = 0 ; i < n ; ++i )
1022     {
1023 
1024         // input types:
1025         // ------------
1026         if ( _input_types[i] < s._input_types[i] )
1027             return true;
1028         if ( s._input_types[i] < _input_types[i] )
1029             return false;
1030 
1031         // bounds:
1032         // -------
1033         if ( _lb[i].comp_with_undef ( s._lb[i] ) )
1034             return true;
1035         if ( s._lb[i].comp_with_undef ( _lb[i] ) )
1036             return false;
1037         if ( _ub[i].comp_with_undef ( s._ub[i] ) )
1038             return true;
1039         if ( s._ub[i].comp_with_undef ( _ub[i] ) )
1040             return false;
1041 
1042         // scaling:
1043         // --------
1044         if ( _scaling[i].comp_with_undef ( s._scaling[i] ) )
1045             return true;
1046         if ( s._scaling[i].comp_with_undef ( _scaling[i] ) )
1047             return false;
1048 
1049         // fixed variables:
1050         // ----------------
1051         if ( _fixed_variables[i].comp_with_undef ( s._fixed_variables[i] ) )
1052             return true;
1053         if ( s._fixed_variables[i].comp_with_undef ( _fixed_variables[i] ) )
1054             return false;
1055 
1056         // periodic variables:
1057         // -------------------
1058         if ( !p1_empty && _periodic_variables[i] != s._periodic_variables[i] )
1059             return _periodic_variables[i];
1060 
1061         // mesh:
1062         // -----
1063         if ( _mesh->get_initial_mesh_size() != s._mesh->get_initial_mesh_size() &&
1064             _mesh->get_min_mesh_size() != s._mesh->get_min_mesh_size() &&
1065             _mesh->get_min_poll_size() != s._mesh->get_min_poll_size() )
1066         {
1067             if ( _mesh->get_initial_mesh_size()[i].comp_with_undef ( s._mesh->get_initial_mesh_size()[i] ) )
1068                 return true;
1069             if ( s._mesh->get_initial_mesh_size()[i].comp_with_undef ( _mesh->get_initial_mesh_size()[i] ) )
1070                 return false;
1071 
1072 
1073             if ( chkm )
1074             {
1075                 if ( _mesh->get_min_mesh_size()[i].comp_with_undef ( s._mesh->get_min_mesh_size()[i] ) )
1076                     return true;
1077                 if ( s._mesh->get_min_mesh_size()[i].comp_with_undef ( _mesh->get_min_mesh_size()[i] ) )
1078                     return false;
1079             }
1080             if ( chkp )
1081             {
1082                 if ( _mesh->get_min_poll_size()[i].comp_with_undef ( s._mesh->get_min_poll_size()[i] ) )
1083                     return true;
1084                 if ( s._mesh->get_min_poll_size()[i].comp_with_undef ( _mesh->get_min_poll_size()[i] ) )
1085                     return false;
1086             }
1087         }
1088     }
1089 
1090     // both signatures are equal:
1091     return false;
1092 }
1093