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   SMesh.cpp
38   \brief  Class for the MADS mesh (implementation)
39   \author Sebastien Le Digabel
40   \date   2010-04-06
41   \see    SMesh.hpp
42 */
43 #include "SMesh.hpp"
44 
45 
46 
47 /*-----------------------------------------------------------*/
48 /*                    update the mesh                        */
49 /*-----------------------------------------------------------*/
update(NOMAD::success_type success,const NOMAD::Direction * dir)50 void NOMAD::SMesh::update ( NOMAD::success_type success , const NOMAD::Direction *dir) // , const NOMAD::OrthogonalMesh * mesh )
51 {
52 	// defaults:
53 	//  full success: lk = lk - 1
54 	//  failure     : lk = lk + 1
55 
56 
57 	if ( success == NOMAD::FULL_SUCCESS )
58     {
59 		_mesh_index -= _coarsening_step;
60 		if ( _mesh_index < -NOMAD::L_LIMITS )
61 			_mesh_index = -NOMAD::L_LIMITS;
62 	}
63 	else if ( success == NOMAD::UNSUCCESSFUL )
64 		_mesh_index -= _refining_step;
65 
66 	if ( _mesh_index > _max_mesh_index )
67 		_max_mesh_index = _mesh_index;
68 
69 
70 	if ( _mesh_index < _min_mesh_index )
71 		_min_mesh_index = _mesh_index;
72 }
73 
74 /*-----------------------------------------------------------*/
75 /* Update the provided mesh indices (the Mesh is unchanged). */
76 /*-----------------------------------------------------------*/
update(NOMAD::success_type success,NOMAD::Point & mesh_indices,const NOMAD::Direction * dir) const77 void NOMAD::SMesh::update ( NOMAD::success_type success , NOMAD::Point & mesh_indices, const NOMAD::Direction *dir ) const
78 {
79 
80 	if ( mesh_indices.is_defined() )
81 	{
82 		for (int i=0; i < mesh_indices.size() ; i++)
83 		{
84 			if ( success == NOMAD::FULL_SUCCESS )
85 			{
86 				mesh_indices[i] -= _coarsening_step;
87 				if ( mesh_indices[i] < -NOMAD::L_LIMITS )
88 					mesh_indices[i] = -NOMAD::L_LIMITS;
89 			}
90 			else if ( success == NOMAD::UNSUCCESSFUL )
91 				mesh_indices[i] -= _refining_step;
92 		}
93 	}
94 }
95 
96 
97 /*-----------------------------------------------------------*/
98 /*              manually set the mesh index                  */
99 /*-----------------------------------------------------------*/
set_mesh_indices(const NOMAD::Point & r)100 void NOMAD::SMesh::set_mesh_indices ( const NOMAD::Point & r )
101 {
102   if (!r.is_defined())
103 	  _mesh_index=0;
104   else
105 	  _mesh_index=r[0].NOMAD::Double::round();
106 
107   if ( _mesh_index > _max_mesh_index )
108     _max_mesh_index = _mesh_index;
109   if ( _mesh_index < _min_mesh_index )
110     _min_mesh_index = _mesh_index;
111 }
112 
113 
114 
115 /*-----------------------------------------------------------*/
116 /*             set the limit mesh index (max value)          */
117 /*-----------------------------------------------------------*/
set_limit_mesh_index(int l)118 void NOMAD::SMesh::set_limit_mesh_index ( int l )
119 {
120     _limit_mesh_index=l;
121 }
122 
123 
124 
125 /*-----------------------------------------------------------*/
126 /*                           display                         */
127 /*-----------------------------------------------------------*/
display(const NOMAD::Display & out) const128 void NOMAD::SMesh::display ( const NOMAD::Display & out ) const
129 {
130   out << "n                       : " << get_n()                   << std::endl
131       << "mesh update basis       : " << _update_basis        << std::endl
132       << "mesh coarsening step: " << _coarsening_step << std::endl
133       << "mesh refining step  : " << _refining_step   << std::endl
134       << "initial mesh size       : "
135       << "(" << _delta_0 << " )" << std::endl;
136   out << "minimal mesh size       : ";
137   if ( _delta_min.is_defined() )
138     out << "(" << _delta_min << " )" << std::endl;
139   else
140     out << "none";
141   out << std::endl
142       << "minimal poll size       : ";
143   if ( _Delta_min_is_defined )
144     out << "(" << _Delta_min << " )" << std::endl;
145   else
146     out << "none";
147   out << std::endl;
148 }
149 
150 /*----------------------------------------------------------*/
151 /*  check the stopping conditions on the minimal poll size  */
152 /*  and on the minimal mesh size                            */
153 /*----------------------------------------------------------*/
check_min_mesh_sizes(bool & stop,NOMAD::stop_type & stop_reason) const154 void NOMAD::SMesh::check_min_mesh_sizes ( bool             & stop           ,
155 					 NOMAD::stop_type & stop_reason      ) const
156 {
157   if ( stop )
158     return;
159 
160   // 1. mesh index tests:
161   if ( abs ( _mesh_index ) > NOMAD::L_LIMITS )
162   {
163     stop        = true;
164     stop_reason = NOMAD::L_LIMITS_REACHED;
165   }
166 
167   // 2. delta_k^p (poll size) tests:
168   if ( check_min_poll_size_criterion ( ) )
169   {
170     stop        = true;
171     stop_reason = NOMAD::DELTA_P_MIN_REACHED;
172   }
173 
174   // 3. delta_k^m (mesh size) tests:
175   if ( check_min_mesh_size_criterion ( ) )
176   {
177     stop        = true;
178     stop_reason = NOMAD::DELTA_M_MIN_REACHED;
179   }
180 }
181 
182 /*-----------------------------------------------------------*/
183 /*              check the minimal poll size (private)        */
184 /*-----------------------------------------------------------*/
check_min_poll_size_criterion() const185 bool NOMAD::SMesh::check_min_poll_size_criterion ( ) const
186 {
187   if ( !_Delta_min_is_defined )
188     return false;
189   NOMAD::Point Delta;
190   return get_Delta ( Delta  );
191 }
192 
193 /*-----------------------------------------------------------*/
194 /*              check the minimal mesh size (private)        */
195 /*-----------------------------------------------------------*/
check_min_mesh_size_criterion() const196 bool NOMAD::SMesh::check_min_mesh_size_criterion ( ) const
197 {
198   if ( !_delta_min.is_defined() )
199     return false;
200   NOMAD::Point delta;
201   return get_delta ( delta );
202 }
203 
204 /*----------------------------------------------------------------*/
205 /*  get delta (mesh size parameter)                             */
206 /*       delta^k = delta^0 \tau^{ell_0^+ - ell_k^+}           */
207 /*----------------------------------------------------------------*/
208 /*  the function also returns true if one value is < delta_min    */
209 /*  (stopping criterion MIN_MESH_SIZE)                            */
210 /*----------------------------------------------------------------*/
get_delta(NOMAD::Point & delta) const211 bool NOMAD::SMesh::get_delta ( NOMAD::Point & delta ) const
212 {
213 	delta.reset ( _n );
214 
215     bool delta_min_is_defined=_delta_min.is_defined();
216 
217 
218 	// power_of_tau = tau^{ max{0,l0} - max{0,lk} }:
219 	NOMAD::Double power_of_tau
220     = pow ( _update_basis.value() ,
221 		   ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) -
222 		   ( (_mesh_index          > 0) ? _mesh_index          : 0)   );
223 
224 	bool stop    = false;
225 
226 	// delta^k = power_of_tau * delta^0:
227 	for ( int i = 0 ; i < _n ; ++i )
228 	{
229 		delta[i] = _delta_0[i] * power_of_tau;
230 		if ( !stop && delta_min_is_defined && delta[i] < _delta_min[i] )
231 			stop = true;
232 
233 	}
234 
235 	return stop;
236 }
237 
238 /*----------------------------------------------------------------*/
239 /*  get delta (mesh size parameter)                             */
240 /*       delta^k = delta^0 \tau^{ell_0^+ - ell_k^+}           */
241 /*----------------------------------------------------------------*/
get_delta(int i) const242 NOMAD::Double NOMAD::SMesh::get_delta ( int i ) const
243 {
244 
245 
246     // power_of_tau = tau^{ max{0,l0} - max{0,lk} }:
247     NOMAD::Double power_of_tau
248     = pow ( _update_basis.value() ,
249            ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) -
250            ( (_mesh_index          > 0) ? _mesh_index          : 0)   );
251 
252 
253     NOMAD::Double delta = _delta_0[i] * power_of_tau;
254 
255     return delta;
256 }
257 
258 
259 /*----------------------------------------------------------------*/
260 /*  get delta_max (the larget mesh size)                             */
261 /*----------------------------------------------------------------*/
get_delta_max() const262 NOMAD::Point NOMAD::SMesh::get_delta_max ( ) const
263 {
264 
265 	NOMAD::Point delta_max ( _n );
266 
267 	// power_of_tau = tau^{ max{0,l0} - max{0,lk} }:
268 	NOMAD::Double power_of_tau
269     = pow ( _update_basis.value() ,
270 		   ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) -
271 		   ( (_min_mesh_index          > 0) ? _min_mesh_index          : 0)   );
272 
273 	// delta^k = power_of_tau * delta^0:
274 	for ( int i = 0 ; i < _n ; ++i )
275 		delta_max[i] = _delta_0[i] * power_of_tau;
276 
277 	return delta_max;
278 }
279 
280 
281 /*-------------------------------------------------------------------*/
282 /*  get Delta (poll size parameter)                                */
283 /*       Delta^k = Delta^m_k \tau^{ |ell_k|/2 }                    */
284 /*                 = delta^0 \tau^{ell_0^+ - ell_k^+ + |ell_k|/2}  */
285 /*-------------------------------------------------------------------*/
286 /*  the function also returns true if all values are < Delta_min   */
287 /*-------------------------------------------------------------------*/
get_Delta(NOMAD::Point & Delta) const288 bool NOMAD::SMesh::get_Delta ( NOMAD::Point & Delta ) const
289 {
290 
291 	Delta.reset ( _n );
292 
293 	// power_of_tau = tau^{ max{0,l0} - max{0,lk} + |lk|/2}:
294 	NOMAD::Double power_of_tau
295     = pow ( _update_basis.value() , abs(_mesh_index) / 2.0             +
296 		   ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) -
297 		   ( (_mesh_index          > 0) ? _mesh_index          : 0)   );
298 
299 	bool stop    = true;
300 
301 	// Delta^k = power_of_tau * Delta^0:
302 	for ( int i = 0 ; i < _n ; ++i )
303 	{
304 		Delta[i] = _Delta_0[i] * power_of_tau;
305 		if ( !_Delta_min_is_complete || Delta[i] >= _Delta_min[i] )
306 			stop = false;
307 
308         if ( _Delta_min_is_defined && _Delta_min[i].is_defined() && Delta[i] < _Delta_min[i] )
309             Delta[i]=_Delta_min[i];
310 	}
311 
312 	return stop;
313 }
314 
315 /*-------------------------------------------------------------------*/
316 /*  get Delta (poll size parameter)                                */
317 /*       Delta^k = Delta^m_k \tau^{ |ell_k|/2 }                    */
318 /*                 = delta^0 \tau^{ell_0^+ - ell_k^+ + |ell_k|/2}  */
319 /*--------------------------------------------------------------*/
320 /*  the function returns Delta >= Delta_min                     */
321 /*--------------------------------------------------------------*/
get_Delta(int i) const322 NOMAD::Double NOMAD::SMesh::get_Delta ( int i ) const
323 {
324 
325     // power_of_tau = tau^{ max{0,l0} - max{0,lk} + |lk|/2}:
326     NOMAD::Double power_of_tau
327     = pow ( _update_basis.value() , abs(_mesh_index) / 2.0             +
328            ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) -
329            ( (_mesh_index          > 0) ? _mesh_index          : 0)   );
330 
331     NOMAD::Double Delta = _Delta_0[i] * power_of_tau;
332 
333     if ( _Delta_min_is_defined && _Delta_min[i].is_defined() && Delta < _Delta_min[i] )
334             Delta=_Delta_min[i];
335 
336     return Delta;
337 }
338 
339 
scale_and_project(int i,const NOMAD::Double & l) const340 NOMAD::Double NOMAD::SMesh::scale_and_project(int i, const NOMAD::Double & l) const
341 {
342 	NOMAD::Double delta = get_delta ( i );
343 	NOMAD::Double Delta = get_Delta ( i );
344 
345 
346 	if ( delta.is_defined() && Delta.is_defined() && i <= _n)
347 	{
348 		NOMAD::Double d= Delta / delta * l;
349 		return d.NOMAD::Double::round()*delta;
350 	}
351 	else
352 		throw NOMAD::Exception ( "SMesh.cpp" , __LINE__ ,
353 								"Mesh scaling and projection cannot be performed!" );
354 
355 }
356 
357 
358 
359 
get_mesh_ratio_if_success(void) const360 NOMAD::Point NOMAD::SMesh::get_mesh_ratio_if_success ( void ) const
361 {
362 
363 	NOMAD::Double power_of_tau
364     = pow ( _update_basis.value() ,
365 		   ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) -
366 		   ( (_mesh_index          > 0) ? _mesh_index          : 0)   );
367 
368 	NOMAD::Double power_of_tau_if_success
369 	= pow ( _update_basis.value() ,
370 		   ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) -
371 		   ( (_mesh_index - _coarsening_step          > 0) ? _mesh_index - _coarsening_step : 0)   );
372 
373 	try
374 	{
375 		NOMAD::Double ratio_scalaire = power_of_tau_if_success/power_of_tau;
376 		return NOMAD::Point( _n , ratio_scalaire );
377 	}
378 	catch ( NOMAD::Double::Invalid_Value & )
379 	{
380 		return NOMAD::Point( _n,-1 );
381 	}
382 }
383