1 /*  _______________________________________________________________________
2 
3     DAKOTA: Design Analysis Kit for Optimization and Terascale Applications
4     Copyright 2014-2020 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
5     This software is distributed under the GNU Lesser General Public License.
6     For more information, see the README file in the top Dakota directory.
7     _______________________________________________________________________ */
8 
9 #ifdef _WIN32
10 #include "dakota_windows.h"
11 #define dlopen(x,y) LoadLibrary(x)
12 #define find_dlsym(a,b,c) (a = (dl_constructor_t)GetProcAddress((HINSTANCE)(b),c))
13 #define dlclose(x) FreeLibrary((HMODULE)x)
14 #define NO_DLERROR
15 #else
16 #include <dlfcn.h>
17 #define find_dlsym(a,b,c) (a = (dl_constructor_t)dlsym(b,c))
18 #undef NO_DLERROR
19 #endif
20 #include <stdarg.h>
21 #include "DLSolver.hpp"
22 #include "ProblemDescDB.hpp"
23 
24 #ifdef DLSOLVER_DEBUG_UNLOCK
25 // This is only needed for the simplest example, dlsolvers/dl_npsol.C,
26 // which uses as much of DAKOTA's machinery for NPSOL as possible.
27 // (This machinery is compiled into DAKOTA unless configured with --without-npsol).
28 // The corresponding dl_npsol.dll is not loaded until the database is locked,
29 // but dl_npsol.dll then invokes "new NPSOLOptimizer(...)", which needs to
30 // have the database unlocked.  Note that unlocking then may give wrong results
31 // in multi-specification runs.  The configure machinery does not know about
32 // compilation with -DDLSOLVER_DEBUG_UNLOCK, since it is only meant for use
33 // in special cases by knowledgeable developers.
34 #define DEBUG_unlock probDescDB.unlock();
35 #define DEBUG_lock probDescDB.lock();
36 #else
37 #define DEBUG_unlock /*default: do nothing*/
38 #define DEBUG_lock   /*default: do nothing*/
39 #endif
40 
41 #define NO_DAKOTA_DLSOLVER_FUNCS_INLINE
42 #include "DLSfuncs.hpp"
43 
44 namespace Dakota {
45 
46  static RealVector const *
continuous_lower_bounds1(Optimizer1 * o)47 continuous_lower_bounds1(Optimizer1 *o)
48 { return &o->M->continuous_lower_bounds(); }
49 
50  static RealVector const *
continuous_upper_bounds1(Optimizer1 * o)51 continuous_upper_bounds1(Optimizer1 *o)
52 { return &o->M->continuous_upper_bounds(); }
53 
54  static RealVector const *
nonlinear_ineq_constraint_lower_bounds1(Optimizer1 * o)55 nonlinear_ineq_constraint_lower_bounds1(Optimizer1 *o)
56 { return &o->M->nonlinear_ineq_constraint_lower_bounds(); }
57 
58  static RealVector const *
nonlinear_ineq_constraint_upper_bounds1(Optimizer1 * o)59 nonlinear_ineq_constraint_upper_bounds1(Optimizer1 *o)
60 { return &o->M->nonlinear_ineq_constraint_upper_bounds(); }
61 
62  static RealVector const *
nonlinear_eq_constraint_targets1(Optimizer1 * o)63 nonlinear_eq_constraint_targets1(Optimizer1 *o)
64 { return &o->M->nonlinear_eq_constraint_targets(); }
65 
66  static RealVector const *
linear_ineq_constraint_lower_bounds1(Optimizer1 * o)67 linear_ineq_constraint_lower_bounds1(Optimizer1 *o)
68 { return &o->M->linear_ineq_constraint_lower_bounds(); }
69 
70  static RealVector const *
linear_ineq_constraint_upper_bounds1(Optimizer1 * o)71 linear_ineq_constraint_upper_bounds1(Optimizer1 *o)
72 { return &o->M->linear_ineq_constraint_upper_bounds(); }
73 
74  static RealVector const *
linear_eq_constraint_targets1(Optimizer1 * o)75 linear_eq_constraint_targets1(Optimizer1 *o)
76 { return &o->M->linear_eq_constraint_targets(); }
77 
78  static RealMatrix const *
linear_eq_constraint_coeffs1(Optimizer1 * o)79 linear_eq_constraint_coeffs1(Optimizer1 *o)
80 { return &o->M->linear_eq_constraint_coeffs(); }
81 
82  static RealMatrix const *
linear_ineq_constraint_coeffs1(Optimizer1 * o)83 linear_ineq_constraint_coeffs1(Optimizer1 *o)
84 { return &o->M->linear_ineq_constraint_coeffs(); }
85 
86  static void
ComputeResponses1(Optimizer1 * o,int mode,int n,double * x)87 ComputeResponses1(Optimizer1 *o, int mode, int n, double *x)
88 {
89 	// without the printf, g++ generates incorrect code
90 	if (n < 0)
91 		printf("ComputeResponses1 has o = #%x, mode = %d, n = %d, x = #%x\n",
92 			o, mode, n, x);
93 	RealVector lx(n);
94 	copy_data(x, n, lx);
95 	o->M->continuous_variables(lx);
96 	o->activeSet_()->request_values(mode);
97 	o->M->evaluate(*o->activeSet_());
98 	}
99 
100  static void
GetFuncs1(Optimizer1 * o,int m0,int m1,double * f)101 GetFuncs1(Optimizer1 *o, int m0, int m1, double *f)
102 {
103 	Response const *R = &o->M->current_response();
104 	RealVector const *RV = &R->function_values();
105 	for(int i = m0; i < m1; i++)
106 		f[i-m0] = (*RV)[i];
107 	}
108 
109  static void
GetGrads1(Optimizer1 * o,int m0,int m1,int n,int is,int js,double * g)110 GetGrads1(Optimizer1 *o, int m0, int m1, int n, int is, int js, double *g)
111 {
112 	int i, i1, j;
113 	Response const *R = &o->M->current_response();
114 	RealMatrix const *RM = &R->function_gradients();
115 	Real const *RV;
116 
117 	for(i1 = 0, i = m0; i < m1; i++, i1 += is) {
118 		RV = (*RM)[i];
119 		for(j = 0; j < n; j++)
120 			g[i1 + j*js] = RV[j];
121 		}
122 	}
123 
124  static void
GetContVars1(Optimizer1 * o,int n,double * x)125 GetContVars1(Optimizer1 *o, int n, double *x)
126 { memcpy(x, &o->M->continuous_variables()[0], n*sizeof(double)); }
127 
128  static void
SetBestContVars1(Optimizer1 * o,int n,double * x)129 SetBestContVars1(Optimizer1 *o, int n, double *x)
130 {
131 	int i;
132 	RealVector X(n);
133 	for(i = 0; i < n; i++)
134 		X[i] = x[i];
135 	o->bestVariables_()->continuous_variables(X);
136 	}
137 
138  static void
SetBestDiscVars1(Optimizer1 * o,int n,int * x)139 SetBestDiscVars1(Optimizer1 *o, int n, int *x)
140 {
141 	int i;
142 	IntVector X(n);
143 	for(i = 0; i < n; i++)
144 		X[i] = x[i];
145 	o->bestVariables_()->discrete_int_variables(X);
146 	}
147 
148  static void
SetBestRespFns1(Optimizer1 * o,int n,double * x)149 SetBestRespFns1(Optimizer1 *o, int n, double *x)
150 {
151 	int i;
152 	RealVector X(n);
153 	for(i = 0; i < n; i++)
154 		X[i] = x[i];
155 	o->bestResponse_()->function_values(X);
156 	}
157 
158  static double
Get_Real1(Optimizer1 * o,const char * name)159 Get_Real1(Optimizer1*o, const char* name)
160 {
161 	return o->problem_description_db().get_real(name);
162 	}
163 
164  static int
Get_Int1(Optimizer1 * o,const char * name)165 Get_Int1(Optimizer1*o, const char* name)
166 {
167 	return o->problem_description_db().get_int(name);
168 	}
169 
170  static bool
Get_Bool1(Optimizer1 * o,const char * name)171 Get_Bool1(Optimizer1*o, const char* name)
172 {
173 	return o->problem_description_db().get_bool(name);
174 	}
175 
176 Dakota_funcs DakFuncs0 = {
177 	fprintf,
178 	abort_handler,
179 	dlsolver_option,
180 	continuous_lower_bounds1,
181 	continuous_upper_bounds1,
182 	nonlinear_ineq_constraint_lower_bounds1,
183 	nonlinear_ineq_constraint_upper_bounds1,
184 	nonlinear_eq_constraint_targets1,
185 	linear_ineq_constraint_lower_bounds1,
186 	linear_ineq_constraint_upper_bounds1,
187 	linear_eq_constraint_targets1,
188 	linear_ineq_constraint_coeffs1,
189 	linear_eq_constraint_coeffs1,
190 	ComputeResponses1,
191 	GetFuncs1,
192 	GetGrads1,
193 	GetContVars1,
194 	SetBestContVars1,
195 	SetBestDiscVars1,
196 	SetBestRespFns1,
197 	Get_Real1,
198 	Get_Int1,
199 	Get_Bool1
200 	};
201 
202  void
cleanup()203 DLSolver::cleanup()
204 {
205 	void *h;
206 	if (h = dlLib) {
207 		dlLib = NULL;
208 		if (dl_destructor)
209 			(*dl_destructor)(&dl_Optimizer);
210 		dlclose(h);
211 		if (pdlLib)
212 			*pdlLib = 0;
213 		}
214 	if (details) {
215 		delete[] details;
216 		details = 0;
217 		}
218 	if (DF) {
219 		delete DF;
220 		DF = 0;
221 		}
222 	}
223 
224  void
botch(const char * fmt,...)225 DLSolver::botch(const char *fmt, ...)
226 {
227 	va_list ap;
228 	va_start(ap, fmt);
229 	fprintf(stderr, "\nDLSolver Error: ");
230 	vfprintf(stderr, fmt, ap);
231 	putc('\n', stderr);
232 	va_end(ap);
233 	fflush(stderr);
234 	cleanup();
235 	abort_handler(-1);
236 	}
237 
DLSolver(Model & model)238 DLSolver::DLSolver(Model& model):
239 	Optimizer1(model, std::shared_ptr<TraitsBase>(new DLSolverTraits())),
240 	dl_core_run(0), dl_destructor(0), dlLib(0)
241 {
242 	const String &dlDetails = probDescDB.get_string("method.dl_solver.dlDetails");
243 	char *s, *s0;
244 	size_t L;
245 	void *h, **vp;
246 
247 	DF = 0;
248 	L = strlen(s0 = dlDetails.data()) + 1;
249 	details = s = new char[L];
250 	if (!s)
251 		botch("new(%lu) failure in DLSolver::DLSolver.", (unsigned long) L);
252 	memcpy(s, s0, L);
253 	vp = probDescDB.get_voidss("method.dl_solver.dlLib");
254 	pdlLib = *vp ? vp : 0;
255 	}
256 
~DLSolver()257 DLSolver::~DLSolver()
258 { cleanup(); }
259 
260  void
core_run()261 DLSolver::core_run()
262 {
263 	Dakota_funcs *df;
264 	Dakota_probsize ps;
265 	char *s, *s0;
266 	typedef void* (*dl_constructor_t)(Optimizer1*, Dakota_funcs*,
267 			dl_core_run_t*, dl_destructor_t*);
268 	dl_constructor_t dl_constructor;
269 	void *h;
270 	if (!dl_core_run) {	// Load the shared library if this is
271 				// the first core_run() invocation.
272 		df = DF = new Dakota_funcs;
273 		if (!df)
274 			botch("new Dakota_Funcs failure");
275 		memcpy(df, &DakFuncs0, sizeof(Dakota_funcs));
276 		for(s0 = s = details; *s > ' '; s++);
277 		if (s == s0)
278 			botch("dlDetails not given for dl_solver.");
279 		if (*s)
280 			*s++ = 0;
281 		if (pdlLib)
282 			h = *pdlLib;
283 		else
284 			h = dlopen(s0, RTLD_NOW/*RTLD_LAZY*/);
285 		if (!h)
286 #ifdef NO_DLERROR
287 			botch("dlopen(\"%s\") failure", s0);
288 #else
289 			botch("dlopen(\"%s\") failure:\n%s", s0, dlerror());
290 #endif
291 		dlLib = h;
292 		if (!(find_dlsym(dl_constructor, h, "dl_constructor")))
293 			botch("dlsym(\"dl_constructor\") failed in \"%s\"", s0);
294 		while(*s && *s <= ' ')
295 			++s;
296 		options = s;
297 		df->Stderr = stderr;
298 		df->dakota_cerr = dakota_cerr;
299 		df->dakota_cout = dakota_cout;
300 		DEBUG_unlock
301 		dl_Optimizer = (*dl_constructor)(this, df, &dl_core_run, &dl_destructor);
302 		DEBUG_lock
303 		}
304 	if (dl_core_run) {
305 		df = DF;
306 		df->Stderr = stderr;
307 		df->dakota_cerr = dakota_cerr;
308 		df->dakota_cout = dakota_cout;
309 		ps.n_var = numContinuousVars_();
310 		ps.n_linc = numLinearConstraints_();
311 		ps.n_nlinc = numNonlinearConstraints_();
312 		ps.n_obj = numObjectiveFunctions_();
313 		ps.maxfe = maxFunctionEvals_();
314 		ps.numgflag = vendorNumericalGradFlag_();
315 		ps.objrecast = localObjectiveRecast_();
316 		df->ps = &ps;
317 		M = iteratedModel_();
318 		(*dl_core_run)(dl_Optimizer, this, options);
319 		}
320 	else
321 		botch("dl_core_run is null in core_run");
322 	}
323 
324  int
dlsolver_option(Opt_Info * Oi)325 dlsolver_option(Opt_Info *Oi)
326 {
327 	char *in, *in0, *s, *val0;
328 	int c;
329 
330 	if (!(in = Oi->begin))
331 		return 0;
332 	while(*in <= ' ')
333 		if (!*in++)
334 			return 0;
335 	Oi->name = in0 = in;
336 	for(; (c = *in) > ' '; ++in) {
337 		if (c == '_')
338 			*in = Oi->und_repl;
339 		else if (c == '=') {
340 			*in = Oi->eq_repl;
341 			break;
342 			}
343 		}
344 	Oi->name_len = in - in0;
345 	if (c == '=')
346 		++in;
347 	if (!*in) {
348  no_val:
349 		Oi->val = 0;
350 		Oi->val_len = 0;
351 		Oi->begin = in;
352 		Oi->all_len = Oi->name_len;
353 		return 1;
354 		}
355 	for(; (c = *in) <= ' '; ++in) {
356 		if (!c)
357 			goto no_val;
358 		}
359 	if (c == '=') {
360 		*in++ = Oi->eq_repl;
361 		while((c = *++in) <= ' ') {
362 			if (!c)
363 				goto no_val;
364 			}
365 		}
366 	Oi->val = val0 = in;
367 	if (c == '\'') {
368 		for(s = in;;) {
369 			c = *++in;
370 			if (c == '\'') {
371 				if (*++in != '\'')
372 					break;
373 				}
374 			else if (!c)
375 				break;
376 			*s++ = c;
377 			}
378 		*s = 0;
379 		Oi->val_len = s - val0;
380 		}
381 	else {
382 		while(*++in > ' ');
383 		Oi->val_len = in - val0;
384 		}
385 	while((c = *in) && c <= ' ')
386 		++in;
387 	Oi->begin = in;
388 	Oi->all_len = in - in0;
389 	return 1;
390 	}
391 
392 } // namespace Dakota
393