3 Local search - A trust region algorithm with BFGS update.
9 #include "stogo_config.h"
14 int local(Trial &T, TBox &box, TBox &domain, double eps_cl, double *mgr,
15 Global &glob, int axis, RCRVector x_av) {
17 int k_max, info, outside ;
18 int k, i, good_enough, iTmp ;
21 double maxgrad, delta, f, f_new, tmp ;
22 double alpha, gamma, beta, d2, s2, nom, den, ro ;
23 double nrm_sd, nrm_hn, snrm_hn, nrm_dl ;
24 RVector x(n), g(n), h_sd(n), h_dl(n), h_n(n), x_new(n), g_new(n) ;
25 RVector s(n),y(n),z(n),w(n) ; // Temporary vectors
26 RMatrix B(n), H(n) ; // Hessian and it's inverse
32 cout << "Local Search, x=" << x << endl;
35 if (box.OutsideBox(x, domain) != 0) {
36 cout << "Starting point is not inside the boundary. Exiting...\n" ;
41 // Check if we are close to a stationary point located previously
42 if (box.CloseToMin(x, &tmp, eps_cl)) {
44 cout << "Close to a previously located stationary point, exiting" << endl;
50 // Initially B and H are equal to the identity matrix
52 for (i=0 ; i<n ; i++) {
57 RVector g_av(x_av.GetLength());
59 f=glob.ObjectiveGradient(x,g,OBJECTIVE_AND_GRADIENT);
63 f=glob.ObjectiveGradient(x_av,g_av,OBJECTIVE_AND_GRADIENT);
71 // Elaborate scheme to initalize delta
72 delta=delta_coef*norm2(g) ;
75 if (!box.InsideBox(z)) {
76 if (box.Intersection(x,g,z)==TRUE) {
78 delta=min(delta,delta_coef*norm2(z)) ;
81 // Algorithm broke down, use INI1
82 delta = (1.0/7)*box.ShortestSide(&iTmp) ;
88 delta = box.ClosestSide(x)*delta_coef ;
90 // Patch to avoid trust region with radius close to zero
91 delta = (1.0/7)*box.ShortestSide(&iTmp) ;
94 delta = delta_coef*box.ShortestSide(&iTmp) ;
98 // Use a simple scheme for the 1D minimization (INI1)
99 delta = (1.0/7.0)*box.ShortestSide(&iTmp) ;
102 k=0 ; good_enough = 0 ; info=LS_New ; outside=0 ;
104 while (good_enough == 0) {
108 cout << "Maximum number of iterations reached\n" ;
114 // Update maximal gradient value
115 maxgrad=max(maxgrad,normInf(g)) ;
117 // Steepest descent, h_sd = -g
122 if (nrm_sd < epsilon) {
123 // Stop criterion (gradient) fullfilled
125 cout << "Gradient small enough" << endl ;
131 // Compute Newton step, h_n = -H*g
132 gemv('N',-1.0, H, g, 0.0, h_n) ;
133 nrm_hn = norm2(h_n) ;
135 if (nrm_hn < delta) {
139 cout << "[Newton step] " ;
143 gemv('N',1.0,B,g,0.0,z) ;
149 alpha=(nrm_sd*nrm_sd)/tmp ; // Normalization (N38,eq. 3.30)
151 nrm_sd=fabs(alpha)*nrm_sd ;
153 if (nrm_sd >= delta) {
154 gamma = delta/nrm_sd ; // Normalization (N38, eq. 3.33)
158 cout << "[Steepest descent] " ;
162 // Combination of Newton and SD steps
167 snrm_hn=nrm_hn*nrm_hn ;
169 den = tmp-s2 + sqrt((tmp-d2)*(tmp-d2)+(snrm_hn-d2)*(d2-s2)) ;
174 // Normalization (N38, eq. 3.31)
178 axpy((1-beta),h_sd,h_dl) ;
180 cout << "[Mixed step] " ;
188 axpy(1.0,h_dl,x_new) ;
190 // Check if x_new is inside the box
191 iTmp=box.OutsideBox(x_new, domain) ;
194 cout << "x_new is outside the box " << endl ;
197 if (outside>max_outside_steps) {
198 // Previous point was also outside, exit
202 else if (iTmp == 2) {
204 cout << " x_new is outside the domain" << endl ;
215 f_new=glob.ObjectiveGradient(x_new,x_new,OBJECTIVE_ONLY);
218 f_new=glob.ObjectiveGradient(x_av,x_new,OBJECTIVE_ONLY);
221 gemv('N',0.5,B,h_dl,0.0,z);
222 ro = (f_new-f) / (dot(g,h_dl) + dot(h_dl,z)); // Quadratic model
230 // Update the Hessian and it's inverse using the BFGS formula
232 glob.ObjectiveGradient(x_new,g_new,GRADIENT_ONLY);
235 glob.ObjectiveGradient(x_av,g_av,GRADIENT_ONLY);
244 // Check curvature condition
246 if (alpha <= sqrt(MacEpsilon)*nrm_dl*norm2(y)) {
248 cout << "Curvature condition violated " ;
253 gemv('N',1.0,B,h_dl,0.0,z) ; // z=Bh_dl
254 beta=-1/dot(h_dl,z) ;
258 // Update Hessian inverse
259 gemv('N',1.0,H,y,0.0,z) ; // z=H*y
260 gemv('T',1.0,H,y,0.0,w) ; // w=y'*H
262 beta=(1+beta/alpha)/alpha ;
264 // It should be possible to do this updating more efficiently, by
265 // exploiting the fact that (h_dl*y'*H) = transpose(H*y*h_dl')
266 ger(beta,h_dl,h_dl,H) ;
267 ger(-1/alpha,z,h_dl,H) ;
268 ger(-1/alpha,h_dl,w,H) ;
271 if (nrm_dl < norm2(x)*epsilon) {
272 // Stop criterion (iteration progress) fullfilled
274 cout << "Progress is marginal" ;
279 // Check if we are close to a stationary point located previously
280 if (box.CloseToMin(x_new, &f_new, eps_cl)) {
281 // Note that x_new and f_new may be overwritten on exit from CloseToMin
283 cout << "Close to a previously located stationary point, exiting" << endl;
290 copy(x_new,x) ; copy(g_new,g) ; f=f_new ;
293 cout << " x=" << x << endl ;
299 cout << "Step is no good, ro=" << ro << " delta=" << delta << endl ;
305 // Make sure the routine returns correctly...
306 // Check if last iterate is outside the boundary
307 if (box.OutsideBox(x, domain) != 0) {
308 info=LS_Out; f=DBL_MAX;
311 if (info == LS_Unstable) {
312 cout << "Local search became unstable. No big deal but exiting anyway\n" ;
316 T.xvals=x ; T.objval=f ;