Xmipp  v3.23.11-Nereus
CNLSolver.cpp
Go to the documentation of this file.
1 /*
2 
3 CONDOR 1.06 - COnstrained, Non-linear, Direct, parallel Optimization
4  using trust Region method for high-computing load,
5  noisy functions
6 Copyright (C) 2004 Frank Vanden Berghen
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation version 2
11 of the License.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 
22 If you want to include this tools in any commercial product,
23 you can contact the author at fvandenb@iridia.ulb.ac.be
24 
25 */
26 
27 #include <stdio.h>
28 #include <memory.h>
29 
30 #ifdef WIN32
31 #include <crtdbg.h>
32 #endif
33 
34 #include "ObjectiveFunction.h"
35 #include "Solver.h"
36 #include "Matrix.h"
37 #include "tools.h"
38 #include "KeepBests.h"
39 #include "IntPoly.h"
40 #include "parallel.h"
41 #include "MultInd.h"
42 #include "VectorChar.h"
43 
44 
45 #ifdef WIN32
46 void (__cdecl *quickHack)(InterPolynomial,int)=NULL;
47 #else
48 void (*quickHack)(InterPolynomial,int)=NULL;
49 #endif
50 
51 // from CTRSSolver:
53  double delta, int *info, int iterMax, double *lambda1,
54  Vector vOBase, ObjectiveFunction *of);
55 char checkForTermination(Vector d, Vector Base, double rhoEnd);
57 
58 extern Vector FullLambda;
59 
60 void fullUpdateOfM(double rho,Vector Base,Matrix data,InterPolynomial poly)
61 {
62  int dim=data.nColumn()-2,i;
63  Vector r(dim);
64  for (i=0; i<data.nLine(); i++)
65  {
66  data.getLine(i,r,dim);
67  if (r.euclidianDistance(Base)<1.5*rho)
68  {
69  r-=Base;
70  poly.updateM(r, ((double**)data)[i][dim]);
71  }
72  }
73 }
74 
75 void CONDOR( double rhoStart, double rhoEnd, int niter,
76  ObjectiveFunction *of, int nnode)
77 {
78  rhoStart=mmax(rhoStart,rhoEnd);
79  int dim=of->dim(), info, k, t, nerror;
80  double rho=rhoStart, delta=rhoStart, rhoNew,
81  lambda1, normD=rhoEnd+1.0, modelStep, reduction, r, valueOF, valueFk, bound, noise;
82  Vector d, tmp;
83  bool improvement, forceTRStep=true, evalNeeded;
84 
86 
87  // pre-create the MultInd indexes to prevent multi-thread problems:
88  cacheMultInd.get(dim,1); cacheMultInd.get(dim,2);
89 
90  parallelInit(nnode, dim, of);
91 
92  of->initData();
93 // points=getFirstPoints(&ValuesF, &nPtsTotal, rhoStart,of);
94 
95  InterPolynomial poly(2, rho, Vector::emptyVector, of->data, of);
96  if (poly.NewtonBasis==NULL)
97  {
98  printf("cannot construct lagrange basis.\n");
99  exit(255);
100  }
101 
102 
103 
104  //Base=poly.vBase;
105  k=poly.kbest;
106  valueFk=poly.valuesF[k];
107 
108  //fprintf(stderr,"init part 1 finished.\n");
109 
110 /* InterPolynomial poly(dim,2,of);
111  for (;;)
112  {
113  // find index k of the best (lowest) value of the function
114  k=findK(ValuesF, nPtsTotal, of, points);
115  Base=points[k].clone();
116  // Base=of->xStart.clone();
117  valueFk=ValuesF[k];
118  // translation:
119  t=nPtsTotal; while (t--) points[t]-=Base;
120 
121  // exchange index 0 and index k (to be sure best point is inside poly):
122  tmp=points[k];
123  points[k]=points[0];
124  points[0]=tmp;
125  ValuesF[k]=ValuesF[0];
126  ValuesF[0]=valueFk;
127  k=0;
128 
129  poly=InterPolynomial(2, nPtsTotal, points, ValuesF);
130  if (poly.NewtonBasis!=NULL) break;
131 
132  // the construction of the first polynomial has failed
133  // delete[] points;
134  free(ValuesF);
135 
136  int kbest=findBest(of->data, of); // return 0 if startpoint is given
137  Vector BaseStart=of->data.getLine(kbest,dim);
138  double vBaseStart=((double**)of->data)[kbest][dim];
139  points=GenerateData(rho, BaseStart, vBaseStart, of, &ValuesF);
140  nPtsTotal=n;
141  }
142 */
143  // update M:
144  fullUpdateOfM(rho,poly.vBase,of->data,poly);
145 
146  //fprintf(stderr,"init part 2 finished.\n");
147  //fprintf(stderr,"init finished.\n");
148 
149  // first of init all variables:
150  parallelImprove(&poly, &k, rho, &valueFk, poly.vBase);
151 
152  // really start in parallel:
154 
155  while (true)
156  {
157 // fprintf(stderr,"rho=%e; fo=%e; NF=%i\n", rho,valueFk,QP_NF);
158  while (true)
159  {
160  // trust region step
161  while (true)
162  {
163 // poly.print();
164  parallelImprove(&poly, &k, rho, &valueFk, poly.vBase);
165 
166  niter--;
167  if ((niter==0)
168  ||(of->isConstrained&&checkForTermination(poly.NewtonPoints[k], poly.vBase, rhoEnd)))
169  {
170  poly.vBase+=poly.NewtonPoints[k];
171  //fprintf(stderr,"rho=%e; fo=%e; NF=%i\n", rho,valueFk,of->getNFE());
172  of->valueBest=valueFk;
173  of->xBest=poly.vBase;
174  // to do : compute H and Lambda
175 
176  Vector vG(dim);
177  Matrix mH(dim,dim);
178  poly.gradientHessian(poly.NewtonPoints[k],vG,mH);
179  of->finalize(vG,mH,FullLambda.clone());
180  return;
181  }
182 
183  // to debug:
184  //fprintf(stderr,"Best Value Objective=%e (nfe=%i)\n", valueFk, of->getNFE());
185 
186  d=ConstrainedL2NormMinimizer(poly,k,delta,&info,1000,&lambda1,poly.vBase,of);
187 
188 // if (d.euclidianNorm()>delta)
189 // {
190 // printf("Warning d to long: (%e > %e)\n", d.euclidianNorm(), delta);
191 // }
192 
193  normD=mmin(d.euclidianNorm(), delta);
194  d+=poly.NewtonPoints[k];
195 
196 // next line is equivalent to reduction=valueFk-poly(d);
197 // BUT is more precise (no rounding error)
198  reduction=-poly.shiftedEval(d,valueFk);
199 
200  //if (normD<0.5*rho) { evalNeeded=true; break; }
201  if ((normD<0.5*rho)&&(!forceTRStep)) { evalNeeded=true; break; }
202 
203  // IF THE MODEL REDUCTION IS SMALL, THEN WE DO NOT SAMPLE FUNCTION
204  // AT THE NEW POINT. WE THEN WILL TRY TO IMPROVE THE MODEL.
205 
206  noise=0.5*mmax(of->noiseAbsolute*(1+of->noiseRelative), condorAbs(valueFk)*of->noiseRelative);
207  if ((reduction<noise)&&(!forceTRStep)) { evalNeeded=true; break; }
208  forceTRStep=false; evalNeeded=false;
209 
210  if (quickHack) (*quickHack)(poly,k);
211  tmp=poly.vBase+d; nerror=0; valueOF=of->eval(tmp, &nerror);
212  of->saveValue(tmp,valueOF,nerror);
213  if (nerror)
214  {
215  // evaluation failed
216  delta*=0.5;
217  if (normD>=2*rho) continue;
218  break;
219  }
220  if (!of->isFeasible(tmp, &r))
221  {
222  printf("violation: %e\n",r);
223  }
224 
225  // update of delta:
226  r=(valueFk-valueOF)/reduction;
227  if (r<=0.1) delta=0.5*normD;
228  else if (r<0.7) delta=mmax(0.5*delta, normD);
229  else delta=mmax(rho+ normD, mmax(1.25*normD, delta));
230  // powell's heuristics:
231  if (delta<1.5*rho) delta=rho;
232 
233  if (valueOF<valueFk)
234  {
235  t=poly.findAGoodPointToReplace(-1, rho, d,&modelStep);
236  k=t; valueFk=valueOF;
237  improvement=true;
238 // fprintf(stderr,"Value Objective=%e\n", valueOF);
239  } else
240  {
241  t=poly.findAGoodPointToReplace(k, rho, d,&modelStep);
242  improvement=false;
243 // fprintf(stderr,".");
244  };
245 
246  if (t<0) { poly.updateM(d, valueOF); break; }
247 
248  // If we are along constraints, it's more important to update
249  // the polynomial with points which increase its quality.
250  // Thus, we will skip this update to use only points coming
251  // from checkIfValidityIsInBound
252 
253  if ((!of->isConstrained)||(improvement)||(reduction>0.0)||(normD<rho)) poly.replace(t, d, valueOF);
254 
255  if (improvement) continue;
256 // if (modelStep>4*rho*rho) continue;
257  if (modelStep>2*rho) continue;
258  if (normD>=2*rho) continue;
259  break;
260  }
261  // model improvement step
262  forceTRStep=true;
263 
264 // fprintf(stderr,"improvement step\n");
265  bound=0.0;
266  if (normD<0.5*rho)
267  {
268  bound=0.5*sqr(rho)*lambda1;
269  if (poly.nUpdateOfM<10) bound=0.0;
270  }
271 
272  parallelImprove(&poly, &k, rho, &valueFk, poly.vBase);
273 
274  // !! change d (if needed):
275  t=poly.checkIfValidityIsInBound(d, k, bound, rho );
276  if (t>=0)
277  {
278  if (quickHack) (*quickHack)(poly,k);
279  tmp=poly.vBase+d; nerror=0; valueOF=of->eval(tmp, &nerror);
280  if (nerror)
281  {
282  Vector GXk(dim);
283  Matrix H(dim,dim);
284  poly.NewtonBasis[t].gradientHessian(poly.NewtonPoints[k],GXk,H);
285  double rhot=rho,vmax;
286 
287  while (nerror)
288  {
289  rhot*=.5;
290  d=LAGMAXModified(GXk,H,rhot,vmax);
291  d+=poly.NewtonPoints[k];
292  tmp=poly.vBase+d; nerror=0; valueOF=of->eval(tmp, &nerror);
293  of->saveValue(tmp,valueOF,nerror);
294  }
295  }
296  poly.replace(t, d, valueOF);
297  if ((valueOF<valueFk)&&
298  (of->isFeasible(tmp))) { k=t; valueFk=valueOF; };
299  continue;
300  }
301 
302  // the model is perfect for this value of rho:
303  // OR
304  // we have crossed a non_linear constraint which prevent us to advance
305  if ((normD<=rho)||(reduction<0.0)) break;
306  }
307 
308 
309 
310  // change rho because no improvement can now be made:
311  if (rho<=rhoEnd) break;
312 
313  //fprintf(stderr,"rho=%e; fo=%e; NF=%i\n", rho,valueFk,of->getNFE());
314 
315  if (rho<16*rhoEnd) rhoNew=rhoEnd;
316  else if (rho<250*rhoEnd) rhoNew=sqrt(rho*rhoEnd);
317  else rhoNew=0.1*rho;
318  delta=mmax(0.5*rho,rhoNew);
319  rho=rhoNew;
320 
321 
322  // update of the polynomial: translation of x[k].
323  // replace BASE by BASE+x[k]
324  poly.translate(poly.NewtonPoints[k]);
325  }
326  parallelFinish();
327 
328  Vector vG(dim);
329  Matrix mH(dim,dim);
330 
331 
332 
333  if (evalNeeded)
334  {
335  tmp=poly.vBase+d; nerror=0; valueOF=of->eval(tmp,&nerror);
336  of->saveValue(tmp,valueOF,nerror);
337  if ((nerror)||(valueOF<valueFk))
338  {
339  poly.vBase+=poly.NewtonPoints[k];
340  poly.gradientHessian(poly.NewtonPoints[k],vG,mH);
341  }
342  else
343  {
344  valueFk=valueOF; poly.vBase=tmp;
345  poly.gradientHessian(d,vG,mH);
346  }
347  } else
348  {
349  poly.vBase+=poly.NewtonPoints[k];
350  poly.gradientHessian(poly.NewtonPoints[k],vG,mH);
351  }
352 
353 
354 // delete[] points; :not necessary: done in destructor of poly which is called automatically:
355  //fprintf(stderr,"rho=%e; fo=%e; NF=%i\n", rho,valueFk,of->getNFE());
356 
357  of->valueBest=valueFk;
358  of->xBest=poly.vBase;
359  of->finalize(vG,mH,FullLambda.clone());
360 
361 }
362 
virtual void saveValue(Vector tmp, double valueOF, int nerror)
virtual void finalize(Vector vG, Matrix mH, Vector vLambda)
Vector * NewtonPoints
Definition: IntPoly.h:47
MultIndCache cacheMultInd
Definition: MultInd.cpp:42
int * mmax
void parallelFinish()
Definition: parallel.cpp:41
void fullUpdateOfM(double rho, Vector Base, Matrix data, InterPolynomial poly)
Definition: CNLSolver.cpp:60
void updateM(Vector newPoint, double valueF)
Definition: IntPoly.cpp:519
double rho
void sqrt(Image< double > &op)
Definition: Vector.h:37
void parallelImprove(InterPolynomial *p, int *_k, double _rho, double *_valueFk, Vector _Base)
Definition: parallel.cpp:36
double euclidianNorm()
Definition: Vector.cpp:222
double mmin(const double t1, const double t2)
Definition: tools.h:69
MultInd * get(unsigned _dim, unsigned _deg)
Definition: MultInd.cpp:242
double euclidianDistance(Vector v)
Definition: Vector.cpp:244
int nColumn()
Definition: Matrix.h:84
Vector clone()
Definition: Vector.cpp:207
#define i
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
doublereal * d
virtual double eval(Vector v, int *nerror)=0
void initConstrainedStep(ObjectiveFunction *of)
Definition: CTRSSolver.cpp:57
int nLine()
Definition: Matrix.h:83
double sqr(const double &t)
Definition: tools.h:99
char isFeasible(Vector vx, double *d=NULL)
unsigned nUpdateOfM
Definition: IntPoly.h:40
Vector LAGMAXModified(Vector G, Matrix H, double rho, double &VMAX)
Definition: MSSolver.cpp:40
double * valuesF
Definition: IntPoly.h:48
void gradientHessian(Vector P, Vector G, Matrix H)
Definition: Poly.cpp:515
char checkForTermination(Vector d, Vector Base, double rhoEnd)
Definition: CTRSSolver.cpp:56
Vector vBase
Definition: IntPoly.h:47
double condorAbs(const double t1)
Definition: tools.h:47
void(* quickHack)(InterPolynomial, int)
Definition: CNLSolver.cpp:48
void startParallelThread()
Definition: parallel.cpp:39
Definition: Matrix.h:38
void parallelInit(int _nnode, int _dim, ObjectiveFunction *_of)
Definition: parallel.cpp:40
Vector getLine(int i, int n=0, int startCol=0)
Definition: Matrix.cpp:1094
int checkIfValidityIsInBound(Vector dd, unsigned k, double bound, double rho)
Definition: IntPoly.cpp:684
static Vector emptyVector
Definition: Vector.h:119
double shiftedEval(Vector Point, double minusVal)
Definition: Poly.cpp:380
Vector ConstrainedL2NormMinimizer(InterPolynomial poly, int k, double delta, int *info, int iterMax, double *lambda1, Vector vOBase, ObjectiveFunction *of)
Definition: CTRSSolver.cpp:59
Polynomial * NewtonBasis
Definition: IntPoly.h:43
Vector FullLambda
Definition: CTRSSolver.cpp:38
void CONDOR(double rhoStart, double rhoEnd, int niter, ObjectiveFunction *of, int nnode)
Definition: CNLSolver.cpp:75
void translate(int k)
double * delta