chiark / gitweb /
bug fix in stogo - rm uninitialized read (doesn't change results since result wasn...
[nlopt.git] / stogo / global.cc
1 /*
2    Multi Dimensional Global Search.
3
4    Author: Steinn Gudmundsson
5    Email: steinng@hotmail.com
6
7    This program is supplied without any warranty whatsoever.
8
9    NB The RNGs seed should be initialized using some timer
10 */
11
12 #include <iostream>
13
14 #include <iterator>
15 #include <algorithm>
16 #include <stack>
17
18 #include "stogo_config.h"
19 #include "global.h"
20 #include "local.h"
21 #include "nlopt-util.h"
22
23 // Timer stuff
24 double   StartTime;
25
26 double MacEpsilon ;
27 int FC=0, GC=0 ;
28
29 int stogo_verbose = 0; /* set to nonzero for verbose output */
30
31 Global::Global(RTBox D, Pobj o, Pgrad g, GlobalParams P): Domain(D) {
32
33   dim=Domain.GetDim();
34   Objective=o;
35   Gradient=g;
36
37   // Initialize parameters
38   maxtime=P.maxtime;
39   maxeval = P.maxeval;
40   numeval = 0;
41   eps_cl=P.eps_cl; mu=P.mu; rshift=P.rshift;
42   det_pnts=P.det_pnts; rnd_pnts=P.rnd_pnts;
43   fbound=DBL_MAX;
44 }
45
46 #if 0 // not necessary; default copy is sufficient 
47 Global& Global::operator=(const Global &G) {
48   // Copy the problem info and parameter settings
49   Domain=G.Domain; Objective=G.Objective;  Gradient=G.Gradient;
50   maxtime=G.maxtime;
51   maxeval = G.maxeval;
52   numeval = G.numeval;
53   eps_cl=G.eps_cl; mu=G.mu; rshift=G.rshift;
54   det_pnts=G.det_pnts; rnd_pnts=G.rnd_pnts;
55   return *this;
56 }
57 #endif
58
59 void Global::FillRegular(RTBox SampleBox, RTBox box) {
60   // Generation of regular sampling points
61   double w;
62   int i, flag, dir;
63   Trial tmpTrial(dim);
64   RVector m(dim), x(dim);
65
66   if (det_pnts>0) {
67     // Add midpoint
68     box.Midpoint(m) ;
69     tmpTrial.xvals=m ; tmpTrial.objval=DBL_MAX ;
70     SampleBox.AddTrial(tmpTrial) ;
71     // Add the rest
72     i=1 ; flag=1 ; dir=0 ;
73     x=m ; 
74     while (i<det_pnts) {
75       w=box.Width(dir) ;
76       x(dir)=m(dir)+flag*rshift*w ;
77       tmpTrial.xvals=x ; 
78       SampleBox.AddTrial(tmpTrial) ;
79       flag=-flag;
80       if (flag==1 && dir<dim) {
81         x(dir)=m(dir) ;
82         dir++ ;
83       }
84       i++ ;
85     }
86   }
87 }
88
89 void Global::FillRandom(RTBox SampleBox, RTBox box) {
90   // Generation of stochastic sampling points
91   Trial tmpTrial(dim);
92
93   tmpTrial.objval=DBL_MAX;
94   for (int i=1 ; i<=rnd_pnts ; i++) {
95     for (int dir=0 ; dir<dim ; dir++)
96       tmpTrial.xvals(dir) = nlopt_urand(box.lb(dir), box.ub(dir));
97     SampleBox.AddTrial(tmpTrial) ;
98   }
99 }
100
101 double Global::NewtonTest(RTBox box, int axis, RCRVector x_av, int *noutside) {
102   // Perform the Newton test
103
104   int info,nout=0;
105   Trial tmpTrial(dim);
106   TBox SampleBox(dim) ;
107   double maxgrad=0 ;
108
109   // Create sampling points
110   FillRegular(SampleBox, box);
111   FillRandom(SampleBox, box);
112
113   // Perform the actual sampling
114   while ( !SampleBox.EmptyBox() ) {
115     SampleBox.RemoveTrial(tmpTrial) ;
116     info = local(tmpTrial, box, Domain, eps_cl, &maxgrad, *this,
117                  axis, x_av) ;
118     // What should we do when info=LS_Unstable?
119     if (info == LS_Out)
120       nout++;
121     if (info == LS_New ) {
122       box.AddTrial(tmpTrial) ;
123
124       if (tmpTrial.objval<=fbound+mu && tmpTrial.objval<=box.fmin+mu) {
125         if (stogo_verbose) {
126           cout << "Found a candidate, x=" << tmpTrial.xvals;
127           cout << " F=" <<tmpTrial.objval << " FC=" << FC << endl;
128         }
129         SolSet.push_back(tmpTrial);
130       }
131 #ifdef GS_DEBUG
132       cout << "Found a stationary point, X= " << tmpTrial.xvals;
133       cout <<" objval=" << tmpTrial.objval << endl;
134 #endif
135     }
136
137     if (!InTime())
138       break;
139   }
140   *noutside=nout;
141   return maxgrad;
142 }
143
144 void Global::ReduceOrSubdivide(RTBox box, int axis, RCRVector x_av) {
145   TBox B1(dim), B2(dim);
146   Trial tmpTrial(dim);
147   double maxgrad;
148   int ns,nout;
149
150   // Monotonicity test has not been implemented yet
151   maxgrad=NewtonTest(box, axis, x_av, &nout);
152   ns=box.NStationary() ;
153   if (ns==0) {
154     // All iterates outside
155     // NB result=Intersection(B,boundary(Domain))
156     Garbage.push(box) ;
157   }
158   else
159     if (ns==1 && nout==0) {
160       // All iterates converge to same point
161       Garbage.push(box) ;
162     }
163     else
164       if ( (ns>1) && (box.LowerBound(maxgrad)>fbound) ) {
165         // Several stationary points found and lower bound > fbound
166         Garbage.push(box) ;
167       }
168       else {
169         // Subdivision
170         B1.ClearBox() ; B2.ClearBox() ;
171         box.split(B1,B2) ;
172         CandSet.push(B1) ; CandSet.push(B2) ;
173       }
174
175   // Update fbound
176   if (box.fmin < fbound) {
177     fbound=box.fmin ;
178 #ifdef GS_DEBUG
179     cout <<"*** Improving fbound, fbound=" << fbound << endl;
180 #endif
181   }
182 }
183
184 void Global::Search(int axis, RCRVector x_av){
185   Trial tmpTrial(dim) ;
186   TBox box(dim), B1(dim), B2(dim);
187   RVector m(dim), x(dim);
188   int inner_iter, outer_iter;
189
190   MacEpsilon=eps(); // Get machine precision
191   if (det_pnts>2*dim+1) {
192     det_pnts=2*dim+1;
193     if (stogo_verbose)
194       cout << "Warning: Reducing det_pnts to " << det_pnts << endl;
195   }
196
197   // Initialize timer
198   StartTime = nlopt_seconds();
199
200   // Clear priority_queues
201   while (!Garbage.empty())
202     Garbage.pop();
203   while (!CandSet.empty())
204     CandSet.pop();
205
206   box=Domain;
207   CandSet.push(box);
208   int done=0 ; outer_iter=0 ;
209
210   while (!done) {
211     outer_iter++ ;
212
213     // Inner loop
214     inner_iter=0 ;
215     while (!CandSet.empty()) {
216       inner_iter++ ;
217       // Get best box from Candidate set
218       box=CandSet.top() ; CandSet.pop() ;
219
220 #ifdef GS_DEBUG
221       cout << "Iteration..." << inner_iter << " #CS=" << CandSet.size()+1 ;
222       cout << " Processing " << box.NStationary() << " trials in the box " <<box;
223 #endif
224       ReduceOrSubdivide(box, axis, x_av);
225
226       if (!InTime()) {
227         done=TRUE;
228         if (stogo_verbose)
229           cout << "The program has run out of time or function evaluations\n";
230         break;
231       }
232
233     } // inner while-loop
234     if (stogo_verbose)
235       cout << endl << "*** Inner loop completed ***" << endl ;
236     
237     // Reduce SolSet if necessary
238     SolSet.erase(remove_if(SolSet.begin(), SolSet.end(),
239                            TrialGT(fbound+mu)),SolSet.end());
240     if (InTime()) {
241       if (stogo_verbose) {
242         cout << "Current set of minimizers (" << SolSet.size() << ")" << endl ;
243         DispMinimizers() ;
244       }
245
246       while (!Garbage.empty()) {
247         box=Garbage.top() ;
248         Garbage.pop() ;
249         // Split box
250         B1.ClearBox() ; B2.ClearBox() ;
251         box.split(B1,B2) ;
252         // Add boxes to Candidate set
253         CandSet.push(B1) ; CandSet.push(B2) ;
254       }
255     }
256   } // Outer while-loop
257
258   if (stogo_verbose) {
259     cout << "Number of outer iterations : " << outer_iter << endl;
260     cout << "Number of unexplored boxes : " << CandSet.size() << endl;
261     cout << "Number of boxes in garbage : " << Garbage.size() << endl;
262     cout << "Number of elements in SolSet : " << SolSet.size() << endl;
263     cout << "Number of function evaluations : " << FC << endl;
264     cout << "Number of gradient evaluations : " << GC << endl;
265   }
266
267   if (axis != -1) {
268     // Return minimizer when doing the AV method
269     tmpTrial=SolSet.back();
270     x_av(axis)=tmpTrial.xvals(0);
271   }
272 }
273
274 /************* Various utility functions ****************/
275 double Global::GetTime()
276 {
277   return nlopt_seconds() - StartTime;
278 }
279
280 bool Global::InTime()
281 {
282  return (maxtime <= 0.0 || GetTime()<maxtime) && (!maxeval || numeval<maxeval);
283 }
284
285 double Global::GetMinValue() {
286   return fbound;
287 }
288
289 void Global::SetMinValue(double new_fb) {
290   fbound=new_fb;
291 }
292
293 void Global::SetDomain(RTBox box) {
294   Domain=box;
295 }
296
297 void Global::GetDomain(RTBox box) {
298   box=Domain;
299 }
300
301 void Global::DispMinimizers() {
302   copy(SolSet.begin(), SolSet.end(), ostream_iterator<Trial>(cout));
303 }
304
305 double Global::OneMinimizer(RCRVector x) {
306   if (NoMinimizers()) return 0.0;
307   for (int i=0;i<x.GetLength();i++) x(i) = SolSet.front().xvals(i);
308   return SolSet.front().objval;
309 }
310
311 bool Global::NoMinimizers() {
312   return SolSet.empty();
313 }
314
315 void Global::ClearSolSet() {
316   SolSet.erase(SolSet.begin(), SolSet.end()) ;
317 }
318
319 void Global::AddPoint(RCRVector x, double f) {
320   Trial T(dim);
321   T.xvals=x; T.objval=f;
322   Domain.AddTrial(T);
323   SolSet.push_back(T);
324 }