1 //------------------------------------------------------------------------
2 // Copyright (C) 1993:
3 // J.C. Meza
4 // Sandia National Laboratories
5 // meza@california.sandia.gov
6 //------------------------------------------------------------------------
7 
8 #include "Opt.h"
9 #include "ioformat.h"
10 
11 using NEWMAT::ColumnVector;
12 using NEWMAT::SymmetricMatrix;
13 
14 namespace OPTPP {
15 
trustregion(NLP1 * nlp,ostream * fout,SymmetricMatrix & H,ColumnVector & search_dir,ColumnVector & sx,real & TR_size,real & step_length,real stpmax,real stpmin)16 int trustregion(NLP1* nlp, ostream *fout,
17 		SymmetricMatrix& H, ColumnVector& search_dir,
18 		ColumnVector& sx, real& TR_size, real& step_length,
19 		real stpmax, real stpmin)
20 {
21 /****************************************************************************
22  *   subroutine trustregion
23  *
24  *   Purpose
25  *   find a step which satisfies the Goldstein-Armijo line search conditions
26  *
27  *        Compute the dogleg step
28  *        Compute the predicted reduction, pred, of the quadratic model
29  *        Compute the actual reduction, ared
30  *        IF ared/pred > eta
31  *          THEN x_vec = x_vec + d_vec
32  *               TR_size >= TR_size
33  *               Compute the gradient g_vec at the new point
34  *          ELSE TR_size < ||d_vec||
35  *
36  *   Parameters
37  *     nlp          -->  pointer to nonlinear problem object
38  *
39  *     search_dir   -->  Vector of length n which specifies the
40  *                       newton direction on input. On output it will
41  *                       contain the step
42  *
43  *     step_length  <-- is a nonnegative variable.
44  *                      On output step_length contains the step size taken
45  *
46  *     ftol  -->  default Value = 1.e-4
47  *                ftol should be smaller than 5.e-1
48  *                suggested value = 1.e-4 for newton methods
49  *                                = 1.e-1 for more exact line searches
50  *     xtol  -->  default Value = 2.2e-16
51  *     gtol  -->  default Value = 0.9
52  *                gtol should be greater than 1.e-4
53  *
54  *                termination occurs when the sufficient decrease
55  *                condition and the directional derivative condition are
56  *                satisfied.
57  *
58  *     stpmin and TR_size are nonnegative input variables which
59  *       specify lower and upper bounds for the step.
60  *       stpmin Default Value = 1.e-9
61  *
62  *   Initial version    Juan Meza November 1994
63  *
64  *
65  *****************************************************************************/
66 
67   // Local variables
68 
69   int n = nlp->getDim();
70   bool debug = nlp->getDebug();
71   bool modeOverride = nlp->getModeOverride();
72 
73   ColumnVector tgrad(n), newton_dir(n), tvec(n), xc(n), xtrial(n);
74   real fvalue, fplus, dnorm;
75   real eta1 = .001;
76   real eta2 = .1;
77   real eta3 = .75;
78   real rho_k;
79   int iter = 0;
80   int iter_max = 100;
81   real dd1, dd2;
82   real ared, pred;
83   int dog_step;
84   real TR_MAX = stpmax;
85   static char *steps[] = {"C", "D", "N", "B"};
86   static bool accept;
87 
88   //
89   // Initialize variables
90   //
91 
92   fvalue = nlp->getF();
93   xc     = nlp->getXc();
94   step_length = 1.0;
95   tgrad      = nlp->getGrad();
96   newton_dir = search_dir;
97 
98   if (debug) {
99     *fout << "\n***************************************";
100     *fout << "***************************************\n";
101     *fout << "\nComputeStep using trustregion\n";
102     *fout << "\tStep   ||step||       ared          pred        TR_size \n";
103   }
104 
105   while (iter < iter_max) {
106     iter++;
107     //
108     // Compute the dogleg step
109     //
110     search_dir = newton_dir;
111     dog_step = dogleg(nlp, fout, H, tgrad, search_dir, sx, dnorm, TR_size, stpmax);
112     step_length = dnorm;
113     //
114     // Compute pred = -g'd - 1/2 d'Hd
115     //
116     dd1  = Dot(tgrad,search_dir);
117     tvec = H * search_dir;
118     dd2  = Dot(search_dir,tvec);
119     pred = -dd1 - dd2/2.0;
120 
121     //
122     // Compute objective function at trial point
123     //
124 
125     xtrial = xc + search_dir;
126     if (modeOverride) {
127       nlp->setX(xtrial);
128       nlp->eval();
129       fplus = nlp->getF();
130     }
131     else
132       fplus  = nlp->evalF(xtrial);
133     ared   = fvalue - fplus;
134 
135     //
136     // Should we take this step ?
137     //
138 
139     rho_k = ared/pred;
140 
141     accept = false;
142     if (rho_k >= eta1) accept = true;
143 
144     //
145     // Update the trust region
146     //
147 
148     if (accept) {
149 
150       //
151       // Do the standard updating
152       //
153 
154       if (rho_k <= eta2) {
155 
156 	// Model is just sort of bad
157 	// New trust region will be TR_size/2
158 
159 	if (debug) {
160 	  *fout << "trustregion: rho_k  = " << e(rho_k,14,4)
161 	      << " eta2 = " << e(eta2,14,4) << "\n";
162 	}
163 	TR_size = step_length / 2.0;
164 
165 	if (TR_size < stpmin) {
166 	  *fout << "***** Trust region too small to continue.\n";
167 	  nlp->setX(xc);
168 	  nlp->setF(fvalue);
169 	  nlp->setGrad(tgrad);
170 	  return(-1);
171 	}
172       }
173 
174       else if ((eta3 <= rho_k) && (rho_k <= (2.0 - eta3))) {
175 
176 	// Model is PRETTY good
177 	// Double trust region
178 
179 	if (debug) {
180 	  *fout << "trustregion: rho_k = " << e(rho_k,14,4)
181 	      << " eta3 = " << e(eta3,14,4) << "\n";
182 	}
183 	TR_size = min(2.0*TR_size, TR_MAX);
184       }
185 
186       else {
187 
188 	//
189 	// All other cases
190 	//
191 
192 	TR_size = max(2.0*step_length,TR_size);
193 	TR_size = min(TR_size, TR_MAX);
194 	if (debug) {
195 	  *fout << "trustregion: rho_k = " << e(rho_k,14,4) << "\n";
196 	}
197       }
198     }
199 
200     else {
201 
202       // Model is REALLY bad
203       //
204 
205       TR_size = step_length/10.0;
206 
207       if (debug) {
208 	*fout << "trustregion: rho_k = " << e(rho_k,14,4) << "n"
209 	    << " eta1 = " << e(eta1,14,4) << "\n";
210       }
211       if (TR_size < stpmin) {
212 	*fout << "***** Trust region too small to continue.\n";
213 	nlp->setX(xc);
214 	nlp->setF(fvalue);
215 	nlp->setGrad(tgrad);
216 	return(-1);
217       }
218     }
219 
220     //
221     //  Accept/Reject Step
222     //
223 
224     if (accept) {
225       //
226       // Update x, f, and grad
227       //
228 
229       if (!modeOverride) {
230 	nlp->setX(xtrial);
231 	nlp->setF(fplus);
232 	nlp->evalG();
233       }
234 
235       if (debug) {
236 	*fout << "\t Step     ||step||       ared          pred        TR_size \n";
237 	*fout << "Accept  " << steps[dog_step] << e(step_length,14,4)
238 	      << e(ared,14,4) << e(pred,14,4) << e(TR_size,14,4) << "\n";
239       }
240       return(dog_step);
241     }
242 
243     else {
244       //
245       // Reject step
246       //
247 
248       if (debug) {
249 	*fout << "\t Step     ||step||       ared          pred        TR_size \n";
250 	*fout << "Reject  " << steps[dog_step] << e(step_length,14,4)
251 	      << e(ared,14,4)  << e(pred,14,4)  << e(TR_size,14,4) << "\n";
252       }
253     }
254   }
255   nlp->setX(xc);
256   nlp->setF(fvalue);
257   nlp->setGrad(tgrad);
258   return(-1); // Too many iterations
259 }
260 
261 } // namespace OPTPP
262