MAST
gcmma_optimization_interface.cpp
Go to the documentation of this file.
1 /*
2  * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3  * Copyright (C) 2013-2019 Manav Bhatia
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 // MAST includes
23 #include "base/mast_config.h"
24 
25 
28 _constr_penalty (5.e1),
29 _initial_rel_step (5.e-1),
30 _asymptote_reduction (0.7),
31 _asymptote_expansion (1.2),
32 _max_inner_iters (15) {
33 
34 #if MAST_ENABLE_GCMMA == 0
35  libmesh_error_msg("MAST configured without GCMMA support.");
36 #endif
37 }
38 
39 
40 void
42 
43  if (nm == "constraint_penalty") {
44 
45  libmesh_assert_greater(val, 0.);
46 
47  _constr_penalty = val;
48  }
49  else if (nm == "initial_rel_step") {
50 
51  libmesh_assert_greater(val, 0.);
52 
53  _initial_rel_step = val;
54  }
55  else if (nm == "asymptote_reduction") {
56 
57  libmesh_assert_greater(val, 0.);
58 
60  }
61  else if (nm == "asymptote_expansion") {
62 
63  libmesh_assert_greater(val, 0.);
64 
66  }
67  else
68  libMesh::out
69  << "Unrecognized real parameter: " << nm << std::endl;
70 }
71 
72 
73 void
75 
76  if (nm == "max_inner_iters") {
77 
78  libmesh_assert_greater(val, 0);
79 
80  _max_inner_iters = val;
81  }
82  else
83  libMesh::out
84  << "Unrecognized integer parameter: " << nm << std::endl;
85 }
86 
87 
88 
89 void
91 #if MAST_ENABLE_GCMMA == 1
92 
93  // make sure that all processes have the same problem setup
95 
96  int
97  N = _feval->n_vars(),
98  M = _feval->n_eq() + _feval->n_ineq(),
99  n_rel_change_iters = _feval->n_iters_relative_change();
100 
101  libmesh_assert_greater(N, 0);
102 
103  std::vector<Real> XVAL(N, 0.), XOLD1(N, 0.), XOLD2(N, 0.),
104  XMMA(N, 0.), XMIN(N, 0.), XMAX(N, 0.), XLOW(N, 0.), XUPP(N, 0.),
105  ALFA(N, 0.), BETA(N, 0.), DF0DX(N, 0.),
106  A(M, 0.), B(M, 0.), C(M, 0.), Y(M, 0.), RAA(M, 0.), ULAM(M, 0.),
107  FVAL(M, 0.), FAPP(M, 0.), FNEW(M, 0.), FMAX(M, 0.),
108  DFDX(M*N, 0.), P(M*N, 0.), Q(M*N, 0.), P0(N, 0.), Q0(N, 0.),
109  UU(M, 0.), GRADF(M, 0.), DSRCH(M, 0.), HESSF(M*(M+1)/2, 0.),
110  f0_iters(n_rel_change_iters);
111 
112  std::vector<int> IYFREE(M, 0);
113  std::vector<bool> eval_grads(M, false);
114 
115  Real
116  ALBEFA = 0.1,
117  GHINIT = _initial_rel_step,
118  GHDECR = _asymptote_reduction,
119  GHINCR = _asymptote_expansion,
120  F0VAL = 0.,
121  F0NEW = 0.,
122  F0APP = 0.,
123  RAA0 = 0.,
124  Z = 0.,
125  GEPS =_feval->tolerance();
126 
127 
128  /*C********+*********+*********+*********+*********+*********+*********+
129  C
130  C The meaning of some of the scalars and vectors in the program:
131  C
132  C N = Complex of variables x_j in the problem.
133  C M = Complex of constraints in the problem (not including
134  C the simple upper and lower bounds on the variables).
135  C ALBEFA = Relative spacing between asymptote and mode limit. Lower value
136  C will cause the move limit (alpha,beta) to move closer to asymptote
137  C values (l, u).
138  C GHINIT = Initial asymptote setting. For the first two iterations the
139  C asymptotes (l, u) are defined based on offsets from the design
140  C point as this fraction of the design variable bounds, ie.
141  C l_j = x_j^k - GHINIT * (x_j^max - x_j^min)
142  C u_j = x_j^k + GHINIT * (x_j^max - x_j^min)
143  C GHDECR = Fraction by which the asymptote is reduced for oscillating
144  C changes in design variables based on three consecutive iterations
145  C GHINCR = Fraction by which the asymptote is increased for non-oscillating
146  C changes in design variables based on three consecutive iterations
147  C INNMAX = Maximal number of inner iterations within each outer iter.
148  C A reasonable choice is INNMAX=10.
149  C ITER = Current outer iteration number ( =1 the first iteration).
150  C GEPS = Tolerance parameter for the constraints.
151  C (Used in the termination criteria for the subproblem.)
152  C
153  C XVAL(j) = Current value of the variable x_j.
154  C XOLD1(j) = Value of the variable x_j one iteration ago.
155  C XOLD2(j) = Value of the variable x_j two iterations ago.
156  C XMMA(j) = Optimal value of x_j in the MMA subproblem.
157  C XMIN(j) = Original lower bound for the variable x_j.
158  C XMAX(j) = Original upper bound for the variable x_j.
159  C XLOW(j) = Value of the lower asymptot l_j.
160  C XUPP(j) = Value of the upper asymptot u_j.
161  C ALFA(j) = Lower bound for x_j in the MMA subproblem.
162  C BETA(j) = Upper bound for x_j in the MMA subproblem.
163  C F0VAL = Value of the objective function f_0(x)
164  C FVAL(i) = Value of the i:th constraint function f_i(x).
165  C DF0DX(j) = Derivative of f_0(x) with respect to x_j.
166  C FMAX(i) = Right hand side of the i:th constraint.
167  C DFDX(k) = Derivative of f_i(x) with respect to x_j,
168  C where k = (j-1)*M + i.
169  C P(k) = Coefficient p_ij in the MMA subproblem, where
170  C k = (j-1)*M + i.
171  C Q(k) = Coefficient q_ij in the MMA subproblem, where
172  C k = (j-1)*M + i.
173  C P0(j) = Coefficient p_0j in the MMA subproblem.
174  C Q0(j) = Coefficient q_0j in the MMA subproblem.
175  C B(i) = Right hand side b_i in the MMA subproblem.
176  C F0APP = Value of the approximating objective function
177  C at the optimal soultion of the MMA subproblem.
178  C FAPP(i) = Value of the approximating i:th constraint function
179  C at the optimal soultion of the MMA subproblem.
180  C RAA0 = Parameter raa_0 in the MMA subproblem.
181  C RAA(i) = Parameter raa_i in the MMA subproblem.
182  C Y(i) = Value of the "artificial" variable y_i.
183  C Z = Value of the "minimax" variable z.
184  C A(i) = Coefficient a_i for the variable z.
185  C C(i) = Coefficient c_i for the variable y_i.
186  C ULAM(i) = Value of the dual variable lambda_i.
187  C GRADF(i) = Gradient component of the dual objective function.
188  C DSRCH(i) = Search direction component in the dual subproblem.
189  C HESSF(k) = Hessian matrix component of the dual function.
190  C IYFREE(i) = 0 for dual variables which are fixed to zero in
191  C the current subspace of the dual subproblem,
192  C = 1 for dual variables which are "free" in
193  C the current subspace of the dual subproblem.
194  C
195  C********+*********+*********+*********+*********+*********+*********+*/
196 
197 
198  /*
199  * The USER should now give values to the parameters
200  * M, N, GEPS, XVAL (starting point),
201  * XMIN, XMAX, FMAX, A and C.
202  */
203  // _initi(M,N,GEPS,XVAL,XMIN,XMAX,FMAX,A,C);
204  // Assumed: FMAX == A
205  _feval->_init_dvar_wrapper(XVAL, XMIN, XMAX);
206  // set the value of C[i] to be very large numbers
207  Real max_x = 0.;
208  for (unsigned int i=0; i<N; i++)
209  if (max_x < fabs(XVAL[i]))
210  max_x = fabs(XVAL[i]);
211 
212  int INNMAX=_max_inner_iters, ITER=0, ITE=0, INNER=0, ICONSE=0;
213  /*
214  * The outer iterative process starts.
215  */
216  bool terminate = false, inner_terminate=false;
217  while (!terminate) {
218 
219  std::fill(C.begin(), C.end(), std::max(1.e0*max_x, _constr_penalty));
220  GHINIT = _initial_rel_step,
221  GHDECR = _asymptote_reduction,
222  GHINCR = _asymptote_expansion,
223 
224  ITER=ITER+1;
225  ITE=ITE+1;
226  /*
227  * The USER should now calculate function values and gradients
228  * at XVAL. The result should be put in F0VAL,DF0DX,FVAL,DFDX.
229  */
230  std::fill(eval_grads.begin(), eval_grads.end(), true);
232  F0VAL, true, DF0DX,
233  FVAL, eval_grads, DFDX);
234  if (ITER == 1)
235  // output the very first iteration
236  _feval->_output_wrapper(0, XVAL, F0VAL, FVAL, true);
237 
238  /*
239  * RAA0,RAA,XLOW,XUPP,ALFA and BETA are calculated.
240  */
241  raasta_(&M, &N, &RAA0, &RAA[0], &XMIN[0], &XMAX[0], &DF0DX[0], &DFDX[0]);
242  asympg_(&ITER, &M, &N, &ALBEFA, &GHINIT, &GHDECR, &GHINCR,
243  &XVAL[0], &XMIN[0], &XMAX[0], &XOLD1[0], &XOLD2[0],
244  &XLOW[0], &XUPP[0], &ALFA[0], &BETA[0]);
245  /*
246  * The inner iterative process starts.
247  */
248 
249  // write the asymptote data for the inneriterations
250  _output_iteration_data(ITER, XVAL, XMIN, XMAX, XLOW, XUPP, ALFA, BETA);
251 
252  INNER=0;
253  inner_terminate = false;
254  while (!inner_terminate) {
255 
256  /*
257  * The subproblem is generated and solved.
258  */
259  mmasug_(&ITER, &M, &N, &GEPS, &IYFREE[0], &XVAL[0], &XMMA[0],
260  &XMIN[0], &XMAX[0], &XLOW[0], &XUPP[0], &ALFA[0], &BETA[0],
261  &A[0], &B[0], &C[0], &Y[0], &Z, &RAA0, &RAA[0], &ULAM[0],
262  &F0VAL, &FVAL[0], &F0APP, &FAPP[0], &FMAX[0], &DF0DX[0], &DFDX[0],
263  &P[0], &Q[0], &P0[0], &Q0[0], &UU[0], &GRADF[0], &DSRCH[0], &HESSF[0]);
264  /*
265  * The USER should now calculate function values at XMMA.
266  * The result should be put in F0NEW and FNEW.
267  */
268  std::fill(eval_grads.begin(), eval_grads.end(), false);
270  F0NEW, false, DF0DX,
271  FNEW, eval_grads, DFDX);
272 
274  // if the solution is poor, backtrack
275  std::vector<Real> XMMA_new(XMMA);
276  Real frac = 0.02;
277  while (FNEW[0] > 1.e2) {
278  libMesh::out << "*** Backtracking: frac = "
279  << frac
280  << " constr: " << FNEW[0]
281  << std::endl;
282  for (unsigned int i=0; i<XMMA.size(); i++)
283  XMMA_new[i] = XOLD1[i] + frac*(XMMA[i]-XOLD1[i]);
284 
285  _feval->_evaluate_wrapper(XMMA_new,
286  F0NEW, false, DF0DX,
287  FNEW, eval_grads, DFDX);
288  frac *= frac;
289  }
290  for (unsigned int i=0; i<XMMA.size(); i++)
291  XMMA[i] = XMMA_new[i];
293 
294  if (INNER >= INNMAX) {
295  libMesh::out
296  << "** Max Inner Iter Reached: Terminating! Inner Iter = "
297  << INNER << std::endl;
298  inner_terminate = true;
299  }
300  else {
301  /*
302  * It is checked if the approximations were conservative.
303  */
304  conser_( &M, &ICONSE, &GEPS, &F0NEW, &F0APP, &FNEW[0], &FAPP[0]);
305  if (ICONSE == 1) {
306  libMesh::out
307  << "** Conservative Solution: Terminating! Inner Iter = "
308  << INNER << std::endl;
309  inner_terminate = true;
310  }
311  else {
312  /*
313  * The approximations were not conservative, so RAA0 and RAA
314  * are updated and one more inner iteration is started.
315  */
316  INNER=INNER+1;
317  raaupd_( &M, &N, &GEPS, &XMMA[0], &XVAL[0],
318  &XMIN[0], &XMAX[0], &XLOW[0], &XUPP[0],
319  &F0NEW, &FNEW[0], &F0APP, &FAPP[0], &RAA0, &RAA[0]);
320  }
321  }
322  }
323 
324  /*
325  * The inner iterative process has terminated, which means
326  * that an outer iteration has been completed.
327  * The variables are updated so that XVAL stands for the new
328  * outer iteration point. The fuction values are also updated.
329  */
330  xupdat_( &N, &ITER, &XMMA[0], &XVAL[0], &XOLD1[0], &XOLD2[0]);
331  fupdat_( &M, &F0NEW, &FNEW[0], &F0VAL, &FVAL[0]);
332  /*
333  * The USER may now write the current solution.
334  */
335  _feval->_output_wrapper(ITER, XVAL, F0VAL, FVAL, true);
336  f0_iters[(ITE-1)%n_rel_change_iters] = F0VAL;
337 
338  /*
339  * One more outer iteration is started as long as
340  * ITE is less than MAXITE:
341  */
342  if (ITE == _feval->max_iters()) {
343  libMesh::out
344  << "GCMMA: Reached maximum iterations, terminating! "
345  << std::endl;
346  terminate = true;
347  }
348 
349  // relative change in objective
350  bool rel_change_conv = true;
351  Real f0_curr = f0_iters[n_rel_change_iters-1];
352 
353  for (unsigned int i=0; i<n_rel_change_iters-1; i++) {
354  if (f0_curr > sqrt(GEPS))
355  rel_change_conv = (rel_change_conv &&
356  fabs(f0_iters[i]-f0_curr)/fabs(f0_curr) < GEPS);
357  else
358  rel_change_conv = (rel_change_conv &&
359  fabs(f0_iters[i]-f0_curr) < GEPS);
360  }
361  if (rel_change_conv) {
362  libMesh::out
363  << "GCMMA: Converged relative change tolerance, terminating! "
364  << std::endl;
365  terminate = true;
366  }
367 
368  }
369 
370 #endif //MAST_ENABLE_GCMMA == 1
371 }
372 
373 
374 void
376  const std::vector<Real>& XVAL,
377  const std::vector<Real>& XMIN,
378  const std::vector<Real>& XMAX,
379  const std::vector<Real>& XLOW,
380  const std::vector<Real>& XUPP,
381  const std::vector<Real>& ALFA,
382  const std::vector<Real>& BETA) {
383 
384  libmesh_assert(_feval);
385  libmesh_assert_equal_to(XVAL.size(), _feval->n_vars());
386  libmesh_assert_equal_to(XMIN.size(), _feval->n_vars());
387  libmesh_assert_equal_to(XMAX.size(), _feval->n_vars());
388  libmesh_assert_equal_to(XLOW.size(), _feval->n_vars());
389  libmesh_assert_equal_to(XUPP.size(), _feval->n_vars());
390  libmesh_assert_equal_to(ALFA.size(), _feval->n_vars());
391  libmesh_assert_equal_to(BETA.size(), _feval->n_vars());
392 
393  /*libMesh::out
394  << "****************************************************\n"
395  << " GCMMA: ASYMPTOTE DATA \n"
396  << "****************************************************\n"
397  << std::setw(5) << "Iter: " << i << std::endl
398  << std::setw(5) << "DV"
399  << std::setw(20) << "XMIN"
400  << std::setw(20) << "XLOW"
401  << std::setw(20) << "ALFA"
402  << std::setw(20) << "X"
403  << std::setw(20) << "BETA"
404  << std::setw(20) << "XUP"
405  << std::setw(20) << "XMAX" << std::endl;
406 
407  for (unsigned int j=0; j<_feval->n_vars(); j++)
408  libMesh::out
409  << std::setw(5) << j
410  << std::setw(20) << XMIN[j]
411  << std::setw(20) << XLOW[j]
412  << std::setw(20) << ALFA[j]
413  << std::setw(20) << XVAL[j]
414  << std::setw(20) << BETA[j]
415  << std::setw(20) << XUPP[j]
416  << std::setw(20) << XMAX[j] << std::endl;
417  */
418 }
419 
void xupdat_(int *N, int *ITER, double *XMMA, double *XVAL, double *XOLD1, double *XOLD2)
void sanitize_parallel()
make sure that the analysis is setup consistently across all parallel processes
virtual void set_real_parameter(const std::string &nm, Real val)
void raasta_(int *M, int *N, double *RAA0, double *RAA, double *XMIN, double *XMAX, double *DF0DX, double *DFDX)
void raaupd_(int *M, int *N, double *GEPS, double *XMMA, double *XVAL, double *XMIN, double *XMAX, double *XLOW, double *XUPP, double *F0NEW, double *FNEW, double *F0APP, double *FAPP, double *RAA0, double *RAA)
void conser_(int *M, int *ICONSE, double *GEPS, double *F0NEW, double *F0APP, double *FNEW, double *FAPP)
libMesh::Real Real
void asympg_(int *ITER, int *M, int *N, double *ALBEFA, double *GHINIT, double *GHDECR, double *GHINCR, double *XVAL, double *XMIN, double *XMAX, double *XOLD1, double *XOLD2, double *XLOW, double *XUPP, double *ALFA, double *BETA)
unsigned int max_iters() const
unsigned int n_ineq() const
void mmasug_(int *ITER, int *M, int *N, double *GEPS, int *IYFREE, double *XVAL, double *XMMA, double *XMIN, double *XMAX, double *XLOW, double *XUPP, double *ALFA, double *BETA, double *A, double *B, double *C, double *Y, double *Z, double *RAA0, double *RAA, double *ULAM, double *F0VAL, double *FVAL, double *F0APP, double *FAPP, double *FMAX, double *DF0DX, double *DFDX, double *P, double *Q, double *P0, double *Q0, double *UU, double *GRADF, double *DSRCH, double *HESSF)
virtual void _evaluate_wrapper(const std::vector< Real > &dvars, Real &obj, bool eval_obj_grad, std::vector< Real > &obj_grad, std::vector< Real > &fvals, std::vector< bool > &eval_grads, std::vector< Real > &grads)
This serves as a wrapper around evaluate() and makes sure that the derived class&#39;s implementation is ...
Provides the basic interface API for classes the provide implement optimization problems.
unsigned int n_vars() const
virtual void _output_wrapper(unsigned int iter, const std::vector< Real > &x, Real obj, const std::vector< Real > &fval, bool if_write_to_optim_file)
This serves as a wrapper around evaluate() and makes sure that the derived class&#39;s implementation is ...
virtual void set_integer_parameter(const std::string &nm, int val)
void _output_iteration_data(unsigned int i, const std::vector< Real > &XVAL, const std::vector< Real > &XMIN, const std::vector< Real > &XMAX, const std::vector< Real > &XLOW, const std::vector< Real > &XUPP, const std::vector< Real > &ALFA, const std::vector< Real > &BETA)
MAST::FunctionEvaluation * _feval
virtual void _init_dvar_wrapper(std::vector< Real > &x, std::vector< Real > &xmin, std::vector< Real > &xmax)
This serves as a wrapper around init_dvar() and makes sure that the derived class&#39;s implementation pr...
unsigned int n_eq() const
unsigned int n_iters_relative_change() const
void fupdat_(int *M, double *F0NEW, double *FNEW, double *F0VAL, double *FVAL)