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